#include #include #include "../cshared/copts.h" #include "../cshared/cstr.h" #include "ecc_api.h" #include #include "asn_application.h" #include "EtsiTs103097Certificate.h" #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; static const char * _cfgFile = NULL; static int _debug = 0; static int _xer = 0; static int _view = 0; 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 }; EtsiTs103097Certificate_t * _cert = NULL; EtsiTs103097Certificate_t * _issuer = NULL; char _tbsHash[512]; // has space for issuer hash + signer hash int _tbsHashLength = 0; char _signerHashBuf[256]; // has space for issuer hash const char* _signerHash = &_signerHashBuf[0]; 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)" }, { "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]" }, { 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); 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); 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 { void *buffer; size_t buffer_size; size_t computed_size; }overrun_encoder_key; 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; 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); } // 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); } else{ _tbsHashLength = 32; sha256_calculate(_tbsHash, (const char*)oer, rc.encoded); } } 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)){ // 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 memcpy(_tbsHash+_tbsHashLength, _signerHash, _signerHashLength); 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 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); } 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); } 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, " [signer]"); return -1; } if (_searchPath == NULL) _searchPath = _outPath; if (_keyPath == NULL) _keyPath = _outPath; if(_xer) _view = 1; _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"); return -1; } FILE * f; asn_dec_rval_t rc_d; asn_enc_rval_t rc_e; 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; 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; issuerOps.xer_decoder = IssuerIdentifier_xer_decoder; tbsOps.oer_encoder = ToBeSignedCertificate_oer_encoder; signatureOps.oer_encoder = Signature_oer_encoder; countryOnlyOps.xer_decoder = CountryOnly_xer_decoder; 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; } PublicVerificationKey_PR hashType = PublicVerificationKey_PR_NOTHING; 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); 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); 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; } 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]; _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]; _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; } if (signer){ ASN_STRUCT_FREE(asn_DEF_EtsiTs103097Certificate, signer); } } 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; } 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; } } // generate keys if necessary // buf = name of private key file int rc = -1; 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); break; case PublicVerificationKey_PR_ecdsaBrainpoolP256r1: rc = fill_curve_point_eccP256(&cert->toBeSigned.verifyKeyIndicator.choice.verificationKey.choice.ecdsaBrainpoolP256r1, ecies_brainpoolp256r, buf); break; case PublicVerificationKey_PR_ecdsaBrainpoolP384r1: rc = fill_curve_point_eccP384(&cert->toBeSigned.verifyKeyIndicator.choice.verificationKey.choice.ecdsaBrainpoolP384r1, ecies_brainpoolp384r, buf); 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"); break; case VerificationKeyIndicator_PR_NOTHING: default: fprintf(stderr, "Unknown verification key indicator type\n"); break; } if (rc < 0){ return -1; } if (cert->toBeSigned.encryptionKey){ rc = -1; 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); break; case BasePublicEncryptionKey_PR_eciesBrainpoolP256r1: rc = fill_curve_point_eccP256(&cert->toBeSigned.encryptionKey->publicKey.choice.eciesBrainpoolP256r1, ecies_brainpoolp256r, buf); break; default: fprintf(stderr, "Unknown encryption key curve type\n"); break; } if (rc < 0){ return -1; } } 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) { 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) { return fill_curve_point_eccP384((EccP384CurvePoint_t*)point, curveType, keyPath); } static int fill_curve_point_eccP384(EccP384CurvePoint_t* point, ecc_curve_id curveType, char * keyPath) { void * key = NULL; char x[48], y[48]; int compressed_y; int fsize; int rc = -1; 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); } 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); } } } 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); } rc = 0; } ecc_key_free(key); return rc; }