certgen.c 37 KB
Newer Older
				p = e;
				continue;
			}
			break;
		}
		if(*v == '-'){
			ret = _defaultTime - ret;
		}else{
			ret = _defaultTime + ret;
		}
	}
	else{
		// next try load as integer seconds since epoch
		ret = strtoul(v, &e, 0);
		if (ret == ULONG_MAX || *e){
			ret = 0;
			//next try to convert ISO text representation
			memset(&tm, 0, sizeof(tm));
			if (3 == sscanf(v, "%d-%d-%d", &tm.tm_year, &tm.tm_mon, &tm.tm_mday)){
				tm.tm_mon--; // STARTED FROM 0
				if (tm.tm_year > 500){
					tm.tm_year -= 1900;
				}
				ret = mkitstime32(&tm);
				if (ret == (time_t)-1) {
					fprintf(stderr, "%s: Date format specification error. Use YYY-MM-DD\n", v);
					ret = 0;
				}
			}
		}
	}
	return ret;
}

static int validity_restriction_tag (cxml_handler_t* const _h, cxml_tag_t * const tag)
{
	int rc = 0;
	cert_cxml_handler_t * h = (cert_cxml_handler_t *)_h;
	if (cxml_tag_is_open(tag)){
		int vr_type = -1;
		int nTime;
		const char * v = cxml_tag_attr_value(tag, "type");
		const char *start, *end, *duration;
		if(NULL == v){
			fprintf(stderr, "ERROR: Restriction shall have a type.\n");
			return -1;
		}
		
		if(0 == strcmp("time", v)){
			start    = cxml_tag_attr_value(tag, "start");
			end      = cxml_tag_attr_value(tag, "end");
			duration = cxml_tag_attr_value(tag, "duration");
			if(end && *end){
				vr_type = (start && *start) ? 1 : 0;
			}else if(start && *start && duration && *duration){
				vr_type = 2;
			}else{
				fprintf(stderr, "ERROR: Either end or start and duration shall be specified for time restriction.\n");
				return -1;
			}
		}else if(0 == strcmp("region", v)){
			vr_type = 3;
			vr_type=strtoul(v, NULL,0);
		}else{
			fprintf(stderr, "%s: Unknown validity restriction type.\n", v);
			return -1;
		}
		h->vr_type = vr_type;
		cint8_write(vr_type, &h->ptr, h->end, &rc);
		
		// save time restrictions
		switch(vr_type){
		case 1: /* time_start_and_end */
			nTime = _convert_time(start);
			cint32_write(nTime, &h->ptr, h->end, &rc);
		case 0: /* time_end */
			nTime = _convert_time(end);
			cint32_write(nTime, &h->ptr, h->end, &rc);
			break;
		case 2: /* time_start_and_duration */
			nTime = _convert_time(start);
			cint32_write(nTime, &h->ptr, h->end, &rc);
			nTime = _convert_time(duration);
			cint32_write(nTime, &h->ptr, h->end, &rc);
			break;
		case 3: /* region */
			break;
		default: // opaque
			bookmark_position(h, tag); // for opaque data
		}
	}else{
		if(h->vr_type > 3){
			apply_bookmark_size(h, tag);
		}
		h->vr_type = -1;
	}
	return 0;
}
static int region_none_tag (cxml_handler_t* const _h, cxml_tag_t * const tag)
{
	if (cxml_tag_is_open(tag)){
		cert_cxml_handler_t * h = (cert_cxml_handler_t *)_h;
		return cint8_write(0, &h->ptr, h->end, NULL);
	}
	return 0;
}

static int region_circle_tag (cxml_handler_t* const _h, cxml_tag_t * const tag)
{
	int rc = 0;
	cert_cxml_handler_t * h = (cert_cxml_handler_t *)_h;
	if (cxml_tag_is_open(tag)){
		//region type
		if(0 == cint8_write(1, &h->ptr, h->end, NULL)){
			//latitude and longitude
			rc = location_tag (_h, tag);
			if(0 == rc){
				//radius
				uint32_t n;
				const char * v    = cxml_tag_attr_value(tag, "radius");
				if(NULL == v){
					fprintf(stderr, "ERROR: radius shall be specified for circle.\n");
					return -1;
				}
				n = strtoul(v, &e, 0);
				if( (e[0] == 'k' || e[0] == 'K') && (e[1] == 'm' || e[1] == 'M') )
					n *= 1000;
				if(n > 0xFFFF){
					fprintf(stderr, "ERROR: %ul: radius is too big.\n", n);
					return -1;
				}
				cint16_write(n, &h->ptr, h->end, &rc);
			}
		}
	}
	return rc;
}

static int region_rectangle_tag (cxml_handler_t* const _h, cxml_tag_t * const tag)
{
	int rc;
	cert_cxml_handler_t * h = (cert_cxml_handler_t *)_h;
	if (cxml_tag_is_open(tag)){
		// region type
		rc = cint8_write(2, &h->ptr, h->end, NULL);
		if(0 == rc){
			bookmark_position(h, tag);
		}
	}else{
		rc = apply_bookmark_size(h, tag);
	}
	return rc;
}

static int region_polygon_tag (cxml_handler_t* const _h, cxml_tag_t * const tag)
{
	int rc;
	cert_cxml_handler_t * h = (cert_cxml_handler_t *)_h;
	if (cxml_tag_is_open(tag)){
		// region type
		rc = cint8_write(3, &h->ptr, h->end, NULL);
		if(0 == rc){
			bookmark_position(h, tag);
		}
	}else{
		rc = apply_bookmark_size(h, tag);
	}
	return rc;
}

static int location_tag (cxml_handler_t* const _h, cxml_tag_t * const tag)
{
	int rc = 0;
	if (cxml_tag_is_open(tag)){
		int32_t lat, lon;
		long double d;
		cert_cxml_handler_t * h = (cert_cxml_handler_t *)_h;
		const char * v    = cxml_tag_attr_value(tag, "latitude");
		if(v == NULL){
			fprintf(stderr, "ERROR: Latitude shall be specified for location.\n");
			return -1;
		}
		e = NULL; d = strtold(v, &e);
		if(e[0] == 'm' || (e[0] == 'k' && e[1] == 'm')){
			if(e[0] == 'k') d*=1000.0;
			d = d * _latTMDPerMetter;
		}else{
			if (d <= 90.0 &&  d >= -90.0) d *= 10000000.0; // degree
		}
		lat = (int32_t)floorl(d+_refLat);

		v    = cxml_tag_attr_value(tag, "longitude");
		if(v == NULL){
			fprintf(stderr, "ERROR: Longitude shall be specified for location.\n");
			return -1;
		}
		e = NULL; d = strtold(v, &e);
		if(e[0] == 'm' || (e[0] == 'k' && e[1] == 'm')){
			if(e[0] == 'k') d*=1000.0;
			// convert metters to degree
			d = d * _lonTMDPerMetter;
		}else{
			if (d <= 180.0 &&  d >= -180.0) d *= 10000000.0; // degree
		}
		lon = (int32_t)floorl(d + _refLon);

		cint32_write(lat, &h->ptr, h->end, &rc);
		cint32_write(lon, &h->ptr, h->end, &rc);
	}
	return rc;
}

static const char * _id_dictionaries[] = {
	"iso_3166_1",
	"un_stats",
};

static int region_id_tag (cxml_handler_t* const _h, cxml_tag_t * const tag)
{
	int rc = 0;
	cert_cxml_handler_t * h = (cert_cxml_handler_t *)_h;
	if (cxml_tag_is_open(tag)){
		int value = 0;
		unsigned int uvalue = 0;
		const char * v;

		// region type
		rc = cint8_write(4, &h->ptr, h->end, NULL);

		// region dictionary. use 0 by default
		v = cxml_tag_attr_value(tag, "dictionary");
		if(v == NULL)v = cxml_tag_attr_value(tag, "dict");
		if(v){
			value = STR2ENUM(_id_dictionaries, v);
			if(value<0){
				fprintf(stderr, "%s: Unknown dictionary type\n", v);
				return -1;
			}
		}
		if(cint8_write(value, &h->ptr, h->end, NULL)){
			return -1;
		}
			
		v = cxml_tag_attr_value(tag, "id");
		if(v == NULL){
			fprintf(stderr, "ERROR: Region identifier must be set\n");
			return -1;
		}
		uvalue = strtoul(v, NULL, 0);
		if(uvalue > 0xFFFF){
			fprintf(stderr, "%s: Invalid region identifier\n", v);
			return -1;
		}
		if(cint16_write(uvalue, &h->ptr, h->end, NULL)){
			return -1;
		}
			
		uvalue = 0;
		v = cxml_tag_attr_value(tag, "local");
		if(v){
			uvalue = strtoul(v, NULL, 0);
			if(!cisdigit(*v) || uvalue > 0xFFFF){
				fprintf(stderr, "%s: Invalid region identifier\n", v);
				return -1;
			}
		}
		cintx_write(uvalue, &h->ptr, h->end, &rc);
		if(rc) return -1;
	}
	return rc;
}

static const char * _signature_algorithms[] = {
	"ecdsa_nistp256_with_sha256",
};

static int certificate_signature_tag (cxml_handler_t* const _h, cxml_tag_t * const tag)
{
	int rc = 0;
	cert_cxml_handler_t * h = (cert_cxml_handler_t *)_h;
	if (cxml_tag_is_open(tag)){
		void * key;
		int alg = 0;
		if(h->signer_type == 0){
			// self signed certificate
			key = h->verificationKey;
			if(!key){
				fprintf(stderr, "ERROR: Verification key attribute was not provided for self-signed certificate\n");
				return -1;
			}
		}else{
			const char * v = cxml_tag_attr_value(tag, "algorithm");
			if (v){
				alg = STR2ENUM(_signature_algorithms, v);
				if (alg < 0){
					fprintf(stderr, "%s: Unknown signature algorithm\n", v);
					return -1;
				}
			}

			if (h->signer == NULL){
				fprintf(stderr, "ERROR: Signer certificate name shall be provided\n");
				return -1;
			}

			// load signer certificate
			int plen = strlen(_searchPath) + strlen(h->signer);
			char * path = malloc(plen + 16);

			cvstrncpy(path, plen + 16, _searchPath, "/", h->signer, ".vkey", NULL);
			key = ecc_api_key_private_load(path, alg);
			if (key == NULL){
				fprintf(stderr, "%s: Could not load issuing private key\n", path);
				free(path);
				return -1;
			}
		}
		cint8_write(alg, &h->ptr, h->end, &rc);
		rc = ecc_sign(key, h->buf, h->ptr - h->buf - 1, &h->ptr, h->end - h->ptr);
	}
	return rc;
}

static int  _Begin_Tag(cxml_handler_t* const h, cxml_tag_t * const tag)
{
	fprintf(stderr, "WARNING: %s: Unknown tag", tag->name);
	return 0;
}

static int  _End_Tag(cxml_handler_t* const h, cxml_tag_t * const tag)
{
	return 0;
}
static int  _Text(cxml_handler_t* const h, char * const text, int length)
{return 0;}