asn1certgen.c 21.1 KB
Newer Older
filatov's avatar
filatov committed
#include <stdio.h>
#include <math.h>
#include "../cshared/copts.h"
#include "../cshared/cstr.h"
#include "ecc_api.h"
#include <ctype.h>

#include "asn_application.h"
filatov's avatar
filatov committed
#include "EtsiTs103097Certificate.h"
filatov's avatar
filatov committed
#include "xer_support.h"

#define CERT_MAX_SIZE 0x10000

static const char * _outPath = ".";
static const char * _searchPath = NULL;
static const char * _certName = NULL;
static       char * _profileName = NULL;
static       char * _signerName = NULL;
static ecc_format   _outKeyFormat = ecc_bin;
static const char * _keyPath = NULL;
static int          _force = 0;
static int          _no_gen = 0;
filatov's avatar
filatov committed
static const char * _cfgFile = NULL;
static int          _debug = 0;
static int          _xer = 0;
static int          _view = 0;
filatov's avatar
filatov committed

filatov's avatar
filatov committed
static const char _sha256_emptyString[] = {
	0xe3, 0xb0, 0xc4, 0x42, 0x98, 0xfc, 0x1c, 0x14, 0x9a, 0xfb, 0xf4, 0xc8, 0x99, 0x6f, 0xb9, 0x24,
	0x27, 0xae, 0x41, 0xe4, 0x64, 0x9b, 0x93, 0x4c, 0xa4, 0x95, 0x99, 0x1b, 0x78, 0x52, 0xb8, 0x55
};

static const char _sha384_emptyString[] = {
	0x38, 0xb0, 0x60, 0xa7, 0x51, 0xac, 0x96, 0x38, 0x4c, 0xd9, 0x32, 0x7e, 0xb1, 0xb1, 0xe3, 0x6a,
	0x21, 0xfd, 0xb7, 0x11, 0x14, 0xbe, 0x07, 0x43, 0x4c, 0x0c, 0xc7, 0xbf, 0x63, 0xf6, 0xe1, 0xda,
	0x27, 0x4e, 0xde, 0xbf, 0xe7, 0x6f, 0x65, 0xfb, 0xd5, 0x1a, 0xd2, 0xf1, 0x48, 0x98, 0xb9, 0x5b
};
filatov's avatar
filatov committed

EtsiTs103097Certificate_t * _cert = NULL;
EtsiTs103097Certificate_t * _issuer = NULL;

filatov's avatar
filatov committed
char    _tbsHash[512]; // has space for issuer hash + signer hash
int     _tbsHashLength = 0;
filatov's avatar
filatov committed

filatov's avatar
filatov committed
char    _signerHashBuf[256]; // has space for issuer hash
const char* _signerHash = &_signerHashBuf[0];
filatov's avatar
filatov committed
int    _signerHashLength = 0;

static const char * const _key_formats[] = {
	"bin", "hex", "pem", NULL
};

typedef struct {
	const char * cert;
	const char * vkey;
	const char * vkey_pub;
	const char * ekey;
	const char * ekey_pub;
} extensions_t;

#define EXT_CERT ".oer"
#define EXT_VKEY ".vkey"
#define EXT_EKEY ".ekey"
#define EXT_PUB  "_pub"

static copt_t _options [] = {
	{ "h?", "help", COPT_HELP, NULL,                 "Print this help page" },
	{ "C", "config", COPT_CFGFILE, (void*)&_cfgFile, "Config file path [no cfg file]" },
	{ "o", "out", COPT_STR, (void*)&_outPath,         "Output path [current dir by default]" },
	{ "k", "key-format", COPT_STRENUM, (void*)_key_formats, "Keys output format (bin|hex|pem)[binary by default]" },
	{ "S", "certs", COPT_STR, (void*)&_searchPath, "Certificates search path [Output path by default]" },
	{ "K", "keys",  COPT_STR,  (void*)&_keyPath,       "Private key storage path [Output path by default]" },
	{ "f", "force", COPT_BOOL, (void*)&_force, "Force regenerate existing certificate and keys. [use existing by default]" },
	{ "e", "no-generate", COPT_BOOL, (void*)&_no_gen, "Do not generate keys. [generate if necessary by default]" },
	{ "n", "name", COPT_STR, (void*)&_certName, "Certificate name (take from profile by default)" },
filatov's avatar
filatov committed
	{ "s", "signer", COPT_STR, (void*)&_signerName,   "Signer certificate name [take from profile by default]" },
	{ "D", "debug", COPT_BOOL, (void*)&_debug,        "Dump hashes and other values [false]" },
	{ "v", "view", COPT_BOOL, (void*)&_view,          "View OER certificate [false]" },
	{ "x", "oxer", COPT_BOOL, (void*)&_xer,           "Decode OER certificate to XER [false]" },
filatov's avatar
filatov committed
	{ NULL, NULL, COPT_END, NULL, NULL }
};

char * _bin2hex(char * hex, size_t hlen, const char * bin, size_t blen);

static int is_CurvePoint_empty(EccP256CurvePoint_t* point);
filatov's avatar
filatov committed

static int fill_curve_point_eccP256(EccP256CurvePoint_t* point, ecc_curve_id curveType, char * keyPath);
static int fill_curve_point_eccP384(EccP384CurvePoint_t* point, ecc_curve_id curveType, char * keyPath);
filatov's avatar
filatov committed

static int _issuer_parser_cb(pxml_chunk_type_e _type,
	const void *_chunk_data, size_t _chunk_size, void *_key)
{
	char * f = cstrnstr((const char *)_chunk_data, _chunk_size, "name=\"");
	if (f){
		_signerName = f + 6;
		f = cstrchr(_signerName, '"');
		_signerName = cstrndup(_signerName, f - _signerName);
	}
	return -1;	
}

static asn_dec_rval_t IssuerIdentifier_xer_decoder(const asn_codec_ctx_t *opt_codec_ctx,
	const asn_TYPE_descriptor_t *td, void **struct_ptr,
	const char *opt_mname, const void *buf_ptr, size_t size)
{
	if (_signerName == NULL){
		int stateContext = 0;
		pxml_parse(&stateContext, buf_ptr, size, _issuer_parser_cb, NULL);
	}
	return CHOICE_decode_xer(opt_codec_ctx, td, struct_ptr, opt_mname, buf_ptr, size);
}

static asn_dec_rval_t CountryOnly_xer_decoder(const asn_codec_ctx_t *opt_codec_ctx,
	const asn_TYPE_descriptor_t *td, void **struct_ptr,
	const char *opt_mname, const void *buf_ptr, size_t size)
{
	// for the future to support letter codes
	return NativeInteger_decode_xer(opt_codec_ctx, td, struct_ptr, opt_mname, buf_ptr, size);
}


typedef struct overrun_encoder_key {
filatov's avatar
filatov committed
	void *buffer;
	size_t buffer_size;
	size_t computed_size;
}overrun_encoder_key;

filatov's avatar
filatov committed

static asn_enc_rval_t ToBeSignedCertificate_oer_encoder(const asn_TYPE_descriptor_t *td,
	const asn_oer_constraints_t *constraints, const void *sptr,
	asn_app_consume_bytes_f *cb, void *app_key)
{
	asn_enc_rval_t rc;
	ToBeSignedCertificate_t * tbs = (ToBeSignedCertificate_t*)sptr;
	overrun_encoder_key *a = (overrun_encoder_key*)app_key;
	const char * oer = ((const char*)a->buffer) + a->computed_size;
filatov's avatar
filatov committed
	rc = SEQUENCE_encode_oer(td, constraints, sptr, cb, app_key);
	if (rc.encoded > 0){
		if(_debug){
			char hex[257*2];
			*_bin2hex(hex, sizeof(hex)-1, oer, ((rc.encoded>256)?256:rc.encoded)) = 0;
			fprintf(stderr, "DEBUG: ToBeSigned OER[%ld]=%s\n", rc.encoded, hex);
		}
filatov's avatar
filatov committed
		// calculate hash
		if (tbs->verifyKeyIndicator.present == VerificationKeyIndicator_PR_verificationKey &&
			tbs->verifyKeyIndicator.choice.verificationKey.present == PublicVerificationKey_PR_ecdsaBrainpoolP384r1) {
			_tbsHashLength = 48;
			sha384_calculate(_tbsHash, (const char*)oer, rc.encoded);
filatov's avatar
filatov committed
		}
		else{
			_tbsHashLength = 32;
			sha256_calculate(_tbsHash, (const char*)oer, rc.encoded);
filatov's avatar
filatov committed
		}
	}
	return rc;
}

static ecc_curve_id _pk_type_to_curveid[] = {
	0,
	ecies_nistp256,       //Signature_PR_ecdsaNistP256Signature,
	ecies_brainpoolp256r, //Signature_PR_ecdsaBrainpoolP256r1Signature,
	ecies_brainpoolp384r  //Signature_PR_ecdsaBrainpoolP384r1Signature
};

static ecc_curve_id _pk_type_to_hashid[] = {
	0,
	sha_256,       //Signature_PR_ecdsaNistP256Signature,
	sha_256, //Signature_PR_ecdsaBrainpoolP256r1Signature,
	sha_384  //Signature_PR_ecdsaBrainpoolP384r1Signature
};

static asn_enc_rval_t Signature_oer_encoder(const asn_TYPE_descriptor_t *td,
	const asn_oer_constraints_t *constraints, const void *sptr,
	asn_app_consume_bytes_f *cb, void *app_key)
{
	Signature_t * s = (Signature_t *)sptr;
	if (is_CurvePoint_empty(&s->choice.ecdsaNistP256Signature.rSig)){
filatov's avatar
filatov committed
		// look for signer private key
		ecc_curve_id alg = _pk_type_to_curveid[s->present];
		ecc_hash_id hashId = _pk_type_to_hashid[s->present];
		const char * sName = _signerName;

		if (sName == NULL && _cert->issuer.present == IssuerIdentifier_PR_self)
			sName = _profileName;

		char* pk = cvstrdup(_keyPath, "/", sName, EXT_VKEY, NULL);
		void *k = ecc_key_private_load(pk, alg);
		if (k){
			char h[48];
			int hl = 0;
			// calculate joint hash
filatov's avatar
filatov committed
			memcpy(_tbsHash+_tbsHashLength, _signerHash, _signerHashLength);
filatov's avatar
filatov committed
			switch (hashId)
			{
			case sha_256:
				sha256_calculate(h, _tbsHash, _tbsHashLength + _signerHashLength);
				hl = sha256_hash_size;
				break;
			case sha_384:
				sha384_calculate(h, _tbsHash, _tbsHashLength + _signerHashLength);
				hl = sha384_hash_size;
				break;
			}

			if (_debug){
				char hex[48*3+1];
				*_bin2hex(hex, sizeof(hex), _tbsHash, _tbsHashLength) = 0;
				fprintf(stderr, "DEBUG: ToBeSignedHash[%d]=%s\n", _tbsHashLength, hex);
				*_bin2hex(hex, sizeof(hex), _signerHash, _signerHashLength) = 0;
				fprintf(stderr, "DEBUG: SignerHash[%d]=%s\n", _signerHashLength, hex);
				*_bin2hex(hex, sizeof(hex), h, hl) = 0;
				fprintf(stderr, "DEBUG: JoinedHash[%d]=%s\n",hl, hex);
			}

			// initialize buffers
filatov's avatar
filatov committed
			OCTET_STRING_fromBuf(&s->choice.ecdsaNistP256Signature.rSig.choice.x_only, h, hl);
			OCTET_STRING_fromBuf(&s->choice.ecdsaNistP256Signature.sSig, h, hl);

			ecc_sign(k, h, hl, s->choice.ecdsaNistP256Signature.rSig.choice.x_only.buf, s->choice.ecdsaNistP256Signature.sSig.buf);
		}
	}
	return asn_OP_CHOICE.oer_encoder(td, constraints, sptr, cb, app_key);
}

Denis Filatov's avatar
Denis Filatov committed

static asn_dec_rval_t PublicVerificationKey_oer_decoder(const struct asn_codec_ctx_s *opt_codec_ctx,
	const struct asn_TYPE_descriptor_s *td, const asn_oer_constraints_t *constraints,
	void **struct_ptr, const void *buf_ptr, size_t size)
{
	return asn_OP_CHOICE.oer_decoder(opt_codec_ctx, td, constraints, struct_ptr, buf_ptr, size);
}

static asn_dec_rval_t ServiceSpecificPermissions_oer_decoder(const struct asn_codec_ctx_s *opt_codec_ctx,
	const struct asn_TYPE_descriptor_s *td, const asn_oer_constraints_t *constraints,
	void **struct_ptr, const void *buf_ptr, size_t size)
{
	return asn_OP_CHOICE.oer_decoder(opt_codec_ctx, td, constraints, struct_ptr, buf_ptr, size);
}


filatov's avatar
filatov committed
int main(int argc, char ** argv)
{
	// set default time to the begining of this year
	//_setup_default_time();

	//parse options
	argc = coptions(argc, argv, COPT_HELP_NOVALUES , _options);
	if(argc < 2){
		if(argc<0 && (0-argc)<((sizeof(_options)/sizeof(_options[0]))-1)){
			printf("Unknown option %s\n", argv[0-argc]);
		}
		const char * a = strrchr(argv[0], '/');
		if (a == NULL) a = argv[0];
		coptions_help(stdout, a, COPT_HELP_NOVALUES, _options, "<profile> [signer]");
		return -1;
	}

	if (_searchPath == NULL) _searchPath = _outPath;
	if (_keyPath == NULL)    _keyPath    = _outPath;
	if(_xer) _view = 1;
filatov's avatar
filatov committed
	
	_outKeyFormat = copts_enum_value(_options, 3, _key_formats);
	
	if(argc > 2){
		// set signer certificate file name
		_signerName = argv[2];
	}
	
	if(ecc_api_init()){
		return -1;
	}

	_profileName = cstrdup(cstrlastpathelement(argv[1]));
	if(_profileName){
		char * p = strrchr(_profileName, '.');
		if(p) *p = 0;
	}

	//load XER file
	char * buf = malloc(CERT_MAX_SIZE);
	char * ebuf;
	EtsiTs103097Certificate_t * cert = NULL;

	ebuf = cstrnload(buf, CERT_MAX_SIZE, argv[1]);
	if(ebuf == NULL){
		fprintf(stderr, "%s: Certificate%s not found\n", argv[1], (_view)?"":" profile");
filatov's avatar
filatov committed
		return -1;
	}

	FILE * f;
	asn_dec_rval_t rc_d;
	asn_enc_rval_t rc_e;
filatov's avatar
filatov committed
	asn_TYPE_operation_t issuerOps = *asn_DEF_IssuerIdentifier.op;
	asn_DEF_IssuerIdentifier.op = &issuerOps;

	asn_TYPE_operation_t tbsOps = *asn_DEF_ToBeSignedCertificate.op;
	asn_DEF_ToBeSignedCertificate.op = &tbsOps;

	asn_TYPE_operation_t signatureOps = *asn_DEF_Signature.op;
	asn_DEF_Signature.op = &signatureOps;

	asn_TYPE_operation_t countryOnlyOps = *asn_DEF_CountryOnly.op;
	asn_DEF_CountryOnly.op = &countryOnlyOps;

Denis Filatov's avatar
Denis Filatov committed
	asn_TYPE_operation_t publicVerificationKeyOps = *asn_DEF_PublicVerificationKey.op;
	asn_DEF_PublicVerificationKey.op = &publicVerificationKeyOps;

	asn_TYPE_operation_t serviceSpecificPermissionsOps = *asn_DEF_ServiceSpecificPermissions.op;
	asn_DEF_ServiceSpecificPermissions.op = &serviceSpecificPermissionsOps;

filatov's avatar
filatov committed
	issuerOps.xer_decoder = IssuerIdentifier_xer_decoder;
	tbsOps.oer_encoder = ToBeSignedCertificate_oer_encoder;
	signatureOps.oer_encoder = Signature_oer_encoder;
	countryOnlyOps.xer_decoder = CountryOnly_xer_decoder;
Denis Filatov's avatar
Denis Filatov committed
	publicVerificationKeyOps.oer_decoder = PublicVerificationKey_oer_decoder;
	serviceSpecificPermissionsOps.oer_decoder = ServiceSpecificPermissions_oer_decoder;

	if(_view) {
		char hash[50], hash_hex[256];
		size_t hLen;
		rc_d = asn_decode(NULL, ATS_BASIC_OER, &asn_DEF_EtsiTs103097Certificate, (void**)&cert, buf, ebuf - buf);
		if (rc_d.code != RC_OK){
			fprintf(stderr, "%s: failed to load at position %d\n  %.30s\n", argv[1], (int)rc_d.consumed, buf + rc_d.consumed);
			return -1;
		}
		if (!_xer){
			if (cert->toBeSigned.verifyKeyIndicator.present == VerificationKeyIndicator_PR_verificationKey &&
				cert->toBeSigned.verifyKeyIndicator.choice.verificationKey.present == PublicVerificationKey_PR_ecdsaBrainpoolP384r1) {
				hLen = 48;
				sha384_calculate(hash, (const char*)buf, rc_d.consumed);
			}
			else{
				hLen = 32;
				sha256_calculate(hash, (const char*)buf, rc_d.consumed);
			}
			*_bin2hex(hash_hex, sizeof(hash_hex), hash, hLen) = 0;
		}

		rc_e = asn_encode_to_buffer(NULL, _xer ? ATS_CANONICAL_XER : ATS_NONSTANDARD_PLAINTEXT, &asn_DEF_EtsiTs103097Certificate, cert, buf, CERT_MAX_SIZE);
		if (rc_e.encoded <0){
			fprintf(stderr, "%s: %s encoding failed for %s\n", argv[1], _xer ? "XER" : "text", rc_e.failed_type->name);
			return -1;
		}
		if (!_xer){
			fprintf(stderr, "Hash  : %s\n", hash_hex);
			fprintf(stderr, "Digest: %s\n", hash_hex + (hLen-8) * 2);
		}
		fwrite(buf, 1, rc_e.encoded, stdout);
		return 0;
	}
filatov's avatar
filatov committed

filatov's avatar
filatov committed
	PublicVerificationKey_PR hashType = PublicVerificationKey_PR_NOTHING;
filatov's avatar
filatov committed

	rc_d = asn_decode(NULL, ATS_BASIC_XER, &asn_DEF_EtsiTs103097Certificate, (void**)&cert, buf, ebuf - buf);
	if (rc_d.code != RC_OK){
		fprintf(stderr, "%s: failed to load at position %d\n  %.30s\n", _profileName, (int)rc_d.consumed, buf + rc_d.consumed);
filatov's avatar
filatov committed
		return -1;
	}

	//check signer
	if (!_signerName && cert->issuer.present != IssuerIdentifier_PR_self){
		fprintf(stderr, "%s: unknown signer\n", argv[1]);
		return -1;
	}
	if (_signerName){
		cvstrncpy(buf, CERT_MAX_SIZE, _searchPath, "/", _signerName, ".oer", NULL);
		ebuf = cstrnload(buf, CERT_MAX_SIZE, buf);
		if (ebuf == NULL){
			fprintf(stderr, "%s: signer certificate not found", _signerName);
			return -1;
		}
		// decode it to detect hash algorythm
		asn_dec_rval_t rc_d;
		EtsiTs103097Certificate_t * signer = NULL;
		rc_d = asn_decode(NULL, ATS_BASIC_OER, &asn_DEF_EtsiTs103097Certificate, (void**)&signer, buf, ebuf - buf);
		if (rc_d.code != RC_OK){
			fprintf(stderr, "%s: failed to load signer certificate at position %d\n  %.30s\n", _signerName, (int)rc_d.consumed, buf + rc_d.consumed);
filatov's avatar
filatov committed
			return -1;
		}
		switch (signer->toBeSigned.verifyKeyIndicator.present){
		case VerificationKeyIndicator_PR_verificationKey:
			hashType = signer->toBeSigned.verifyKeyIndicator.choice.verificationKey.present;
			break;
		case VerificationKeyIndicator_PR_reconstructionValue:
			hashType = PublicVerificationKey_PR_ecdsaNistP256;
			break;
		case VerificationKeyIndicator_PR_NOTHING:
			fprintf(stderr, "%s: signer verification indicator type is unknown\n", _signerName);
			return -1;
filatov's avatar
filatov committed
		}

		switch (hashType){
		case PublicVerificationKey_PR_ecdsaBrainpoolP256r1:
		case PublicVerificationKey_PR_ecdsaNistP256:
			if (cert->issuer.present == IssuerIdentifier_PR_NOTHING)
				cert->issuer.present = IssuerIdentifier_PR_sha256AndDigest;
			sha256_calculate(_signerHashBuf, buf, ebuf - buf);
			_signerHash = &_signerHashBuf[0];
filatov's avatar
filatov committed
			_signerHashLength = sha256_hash_size;
			OCTET_STRING_fromBuf(&cert->issuer.choice.sha256AndDigest, &_signerHash[sha256_hash_size-8], 8);
			break;
		case PublicVerificationKey_PR_ecdsaBrainpoolP384r1:
			if (cert->issuer.present == IssuerIdentifier_PR_NOTHING)
				cert->issuer.present = IssuerIdentifier_PR_sha384AndDigest;
			sha384_calculate(_signerHashBuf, buf, ebuf - buf);
			_signerHash = &_signerHashBuf[0];
filatov's avatar
filatov committed
			_signerHashLength = sha384_hash_size;
			OCTET_STRING_fromBuf(&cert->issuer.choice.sha384AndDigest, &_signerHash[sha384_hash_size - 8], 8);
			break;
		case PublicVerificationKey_PR_NOTHING:
			fprintf(stderr, "%s: signer verification key type curve is unknown\n", _signerName);
			return -1;
filatov's avatar
filatov committed
		}
		if (signer){
			ASN_STRUCT_FREE(asn_DEF_EtsiTs103097Certificate, signer);
		}
filatov's avatar
filatov committed
	} else  {
		// self-signed
		// use hash(empty string)
		switch (cert->toBeSigned.verifyKeyIndicator.present){
		case VerificationKeyIndicator_PR_verificationKey:
			hashType = cert->toBeSigned.verifyKeyIndicator.choice.verificationKey.present;
			break;
		case VerificationKeyIndicator_PR_reconstructionValue:
			hashType = PublicVerificationKey_PR_ecdsaNistP256;
			break;
		case VerificationKeyIndicator_PR_NOTHING:
			fprintf(stderr, "%s: signer verification indicator type is unknown\n", _signerName);
			return -1;
filatov's avatar
filatov committed
		}
		switch (hashType) {
		case PublicVerificationKey_PR_ecdsaBrainpoolP256r1:
		case PublicVerificationKey_PR_ecdsaNistP256:
			_signerHash = &_sha256_emptyString[0];
			_signerHashLength = sha256_hash_size;
			break;
		case PublicVerificationKey_PR_ecdsaBrainpoolP384r1:
			_signerHash = &_sha384_emptyString[0];
			_signerHashLength = sha384_hash_size;
			break;
		default:
			fprintf(stderr, "Unknown verification key curve type\n");
			return -1;
		}
filatov's avatar
filatov committed
	}

	// generate keys if necessary
	// buf = name of private key file
filatov's avatar
filatov committed
	cvstrncpy(buf, CERT_MAX_SIZE, _keyPath, "/", _profileName, EXT_VKEY, NULL);
	switch (cert->toBeSigned.verifyKeyIndicator.present){
	case VerificationKeyIndicator_PR_verificationKey:
		switch (cert->toBeSigned.verifyKeyIndicator.choice.verificationKey.present){
		case PublicVerificationKey_PR_ecdsaNistP256:
			rc = fill_curve_point_eccP256(&cert->toBeSigned.verifyKeyIndicator.choice.verificationKey.choice.ecdsaNistP256, ecies_nistp256, buf);
filatov's avatar
filatov committed
			break;
		case PublicVerificationKey_PR_ecdsaBrainpoolP256r1:
			rc = fill_curve_point_eccP256(&cert->toBeSigned.verifyKeyIndicator.choice.verificationKey.choice.ecdsaBrainpoolP256r1, ecies_brainpoolp256r, buf);
filatov's avatar
filatov committed
			break;
		case PublicVerificationKey_PR_ecdsaBrainpoolP384r1:
			rc = fill_curve_point_eccP384(&cert->toBeSigned.verifyKeyIndicator.choice.verificationKey.choice.ecdsaBrainpoolP384r1, ecies_brainpoolp384r, buf);
filatov's avatar
filatov committed
			break;
		default:
			fprintf(stderr, "Unknown verification key curve type\n");
		}
		break;
	case VerificationKeyIndicator_PR_reconstructionValue:
		fprintf(stderr, "TODO: reconstruction value generation is unsupported yet\n");
filatov's avatar
filatov committed
	case VerificationKeyIndicator_PR_NOTHING:
	default:
		fprintf(stderr, "Unknown verification key indicator type\n");
		return -1;
filatov's avatar
filatov committed
	}
	if (cert->toBeSigned.encryptionKey){
filatov's avatar
filatov committed
		cvstrncpy(buf, CERT_MAX_SIZE, _keyPath, "/", _profileName, EXT_EKEY, NULL);
		switch (cert->toBeSigned.encryptionKey->publicKey.present){
		case BasePublicEncryptionKey_PR_NOTHING:
			cert->toBeSigned.encryptionKey->publicKey.present = BasePublicEncryptionKey_PR_eciesNistP256;
		case BasePublicEncryptionKey_PR_eciesNistP256:
			rc = fill_curve_point_eccP256(&cert->toBeSigned.encryptionKey->publicKey.choice.eciesNistP256, ecies_nistp256, buf);
filatov's avatar
filatov committed
			break;
		case BasePublicEncryptionKey_PR_eciesBrainpoolP256r1:
			rc = fill_curve_point_eccP256(&cert->toBeSigned.encryptionKey->publicKey.choice.eciesBrainpoolP256r1, ecies_brainpoolp256r, buf);
filatov's avatar
filatov committed
			break;
		default:
			fprintf(stderr, "Unknown encryption key curve type\n");
filatov's avatar
filatov committed
			break;
		}
filatov's avatar
filatov committed
	}

	cvstrncpy(buf, CERT_MAX_SIZE, _outPath, "/", _profileName, EXT_CERT, NULL);
	f = fopen(buf, "wb");
	if (f == NULL){
		perror(buf);
		return -1;
	}

	_cert = cert;
	// Encode as OER
	rc_e = asn_encode_to_buffer(NULL, ATS_CANONICAL_OER, &asn_DEF_EtsiTs103097Certificate, cert, buf, CERT_MAX_SIZE);
	if (rc_e.encoded <0){
		fprintf(stderr, "%s: OER encoding failed for %s\n", _profileName, rc_e.failed_type->name);
		return -1;
	}

	fwrite(buf, 1, rc_e.encoded, f);
	fclose(f);

	if(cert){
		ASN_STRUCT_FREE(asn_DEF_EtsiTs103097Certificate, cert);
	}
	return 0;
}

static int is_CurvePoint_empty(EccP256CurvePoint_t* point)
filatov's avatar
filatov committed
{
	switch (point->present){
	case EccP256CurvePoint_PR_x_only:
	case EccP256CurvePoint_PR_compressed_y_0:
	case EccP256CurvePoint_PR_compressed_y_1:
		return point->choice.x_only.size < 32;
	case EccP256CurvePoint_PR_uncompressedP256:
		return point->choice.uncompressedP256.x.size < 32 || point->choice.uncompressedP256.y.size < 32;
	default:
		break;
	}
	return 1;
}
static int fill_curve_point_eccP256(EccP256CurvePoint_t* point, ecc_curve_id curveType, char * keyPath)
filatov's avatar
filatov committed
{
	return fill_curve_point_eccP384((EccP384CurvePoint_t*)point, curveType, keyPath);
filatov's avatar
filatov committed
}
static int fill_curve_point_eccP384(EccP384CurvePoint_t* point, ecc_curve_id curveType, char * keyPath)
filatov's avatar
filatov committed
{
filatov's avatar
filatov committed
	char x[48], y[48];
	int compressed_y;
	int fsize;
	char * e_pub = keyPath + strlen(keyPath);
	if(!_force){
		// check for public key
		strcpy(e_pub, EXT_PUB);
		key = ecc_key_public_load(keyPath, curveType);
		if (_debug && key){
			fprintf(stderr, "DEBUG: use pre-generated key %s\n", keyPath);
		}
		*e_pub = 0;
	} else {
		remove(keyPath);
	}
filatov's avatar
filatov committed
	if (key == NULL){
		key = ecc_key_private_load(keyPath, curveType);
		if (key == NULL){
			if (_no_gen){
				fprintf(stderr, "ERROR: Key %s or %s%s not found\n", keyPath, keyPath, EXT_PUB);
				return rc;
			}
			if (_debug){
				fprintf(stderr, "DEBUG: generate key %s\n", keyPath);
			}
			key = ecc_key_gen(curveType);
			ecc_key_private_save(key, keyPath, _outKeyFormat);
			strcpy(e_pub, EXT_PUB);
			ecc_key_public_save(key, keyPath, _outKeyFormat);
		}else{
			if (_debug){
				fprintf(stderr, "DEBUG: use pre-generated key %s\n", keyPath);
			}
filatov's avatar
filatov committed
	}
	fsize = ecc_key_public(key, x, y, &compressed_y);
	if (fsize > 0){
		OCTET_STRING_fromBuf(&point->choice.x_only, x, fsize);
		if (point->present == EccP384CurvePoint_PR_uncompressedP384){
			OCTET_STRING_fromBuf(&point->choice.uncompressedP384.y, y, fsize);
		}
		else if (point->present == EccP384CurvePoint_PR_compressed_y_0 || point->present == EccP384CurvePoint_PR_compressed_y_1){
			point->present = compressed_y ? EccP384CurvePoint_PR_compressed_y_1 : EccP384CurvePoint_PR_compressed_y_0;
		}
		if (_debug){
			char hex [256];
			*_bin2hex(hex, sizeof(hex), x, fsize) = 0;
			fprintf(stderr, "DEBUG: %s_pub.x=%s\n", keyPath, hex);
			*_bin2hex(hex, sizeof(hex), y, fsize) = 0;
			fprintf(stderr, "DEBUG: %s_pub.y=%s\n", keyPath, hex);
		}
filatov's avatar
filatov committed
	}
	ecc_key_free(key);
filatov's avatar
filatov committed
}