int dslink_handshake_read_key_pair(mbedtls_ecdh_context *ctx, char *buf) { mbedtls_ecdh_init(ctx); dslink_handshake_get_group(&ctx->grp); char *q = strchr(buf, ' '); if (!q || *(q + 1) == '\0') { errno = 0; return DSLINK_CRYPT_KEY_DECODE_ERR; } size_t len = (q - buf); unsigned char dec[90]; size_t decLen = 0; if (dslink_base64_url_decode(dec, sizeof(dec), &decLen, (unsigned char *) buf, len) != 0) { return DSLINK_CRYPT_BASE64_URL_DECODE_ERR; } if ((errno = mbedtls_mpi_read_binary(&ctx->d, dec, decLen)) != 0) { return DSLINK_CRYPT_KEY_DECODE_ERR; } len = strlen(buf) - len - 1; if (dslink_base64_url_decode(dec, sizeof(dec), &decLen, (unsigned char *) (q + 1), len) != 0) { return DSLINK_CRYPT_BASE64_URL_DECODE_ERR; } if ((errno = mbedtls_ecp_point_read_binary(&ctx->grp, &ctx->Q, dec, decLen)) != 0) { return DSLINK_CRYPT_KEY_DECODE_ERR; } return 0; }
static int gen_auth_key(mbedtls_ecdh_context *key, const char *tempKey, const char *salt, unsigned char *buf, size_t bufLen) { int ret = 0; size_t olen = 0; if ((errno = dslink_base64_url_decode(buf, bufLen, &olen, (unsigned char *) tempKey, strlen(tempKey))) != 0) { ret = DSLINK_CRYPT_BASE64_URL_DECODE_ERR; goto exit; } if ((errno = mbedtls_ecp_point_read_binary(&key->grp, &key->Qp, buf, olen)) != 0) { ret = DSLINK_HANDSHAKE_INVALID_TMP_KEY; goto exit; } if ((errno = mbedtls_ecdh_calc_secret(key, &olen, buf, bufLen, NULL, NULL)) != 0) { ret = DSLINK_HANDSHAKE_INVALID_TMP_KEY; goto exit; } { size_t saltLen = strlen(salt); size_t len = saltLen + olen; char *in = malloc(len + 1); if (!in) { ret = DSLINK_ALLOC_ERR; goto exit; } memcpy(in, salt, saltLen); memcpy(in + saltLen, (char *) buf, olen); *(in + len) = '\0'; unsigned char auth[32]; mbedtls_sha256((unsigned char *) in, len, auth, 0); free(in); if ((errno = dslink_base64_url_encode(buf, bufLen, &olen, auth, sizeof(auth))) != 0) { ret = DSLINK_CRYPT_BASE64_URL_ENCODE_ERR; } } exit: return ret; }
/* * Parse the public key used for signing. */ static int bootutil_parse_eckey(mbedtls_ecdsa_context *ctx, uint8_t **p, uint8_t *end) { size_t len; mbedtls_asn1_buf alg; mbedtls_asn1_buf param; if (mbedtls_asn1_get_tag(p, end, &len, MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE)) { return -1; } end = *p + len; if (mbedtls_asn1_get_alg(p, end, &alg, ¶m)) { return -2; } if (alg.len != sizeof(ec_pubkey_oid) - 1 || memcmp(alg.p, ec_pubkey_oid, sizeof(ec_pubkey_oid) - 1)) { return -3; } if (param.len != sizeof(ec_secp224r1_oid) - 1|| memcmp(param.p, ec_secp224r1_oid, sizeof(ec_secp224r1_oid) - 1)) { return -4; } if (mbedtls_ecp_group_load_secp224r1(&ctx->grp)) { return -5; } if (mbedtls_asn1_get_bitstring_null(p, end, &len)) { return -6; } if (*p + len != end) { return -7; } if (mbedtls_ecp_point_read_binary(&ctx->grp, &ctx->Q, *p, end - *p)) { return -8; } if (mbedtls_ecp_check_pubkey(&ctx->grp, &ctx->Q)) { return -9; } return 0; }
/* * EC public key is an EC point * * The caller is responsible for clearing the structure upon failure if * desired. Take care to pass along the possible ECP_FEATURE_UNAVAILABLE * return code of mbedtls_ecp_point_read_binary() and leave p in a usable state. */ static int pk_get_ecpubkey( unsigned char **p, const unsigned char *end, mbedtls_ecp_keypair *key ) { int ret; if( ( ret = mbedtls_ecp_point_read_binary( &key->grp, &key->Q, (const unsigned char *) *p, end - *p ) ) == 0 ) { ret = mbedtls_ecp_check_pubkey( &key->grp, &key->Q ); } /* * We know mbedtls_ecp_point_read_binary consumed all bytes or failed */ *p = (unsigned char *) end; return( ret ); }
/* * Parse a SpecifiedECDomain (SEC 1 C.2) and (mostly) fill the group with it. * WARNING: the resulting group should only be used with * pk_group_id_from_specified(), since its base point may not be set correctly * if it was encoded compressed. * * SpecifiedECDomain ::= SEQUENCE { * version SpecifiedECDomainVersion(ecdpVer1 | ecdpVer2 | ecdpVer3, ...), * fieldID FieldID {{FieldTypes}}, * curve Curve, * base ECPoint, * order INTEGER, * cofactor INTEGER OPTIONAL, * hash HashAlgorithm OPTIONAL, * ... * } * * We only support prime-field as field type, and ignore hash and cofactor. */ static int pk_group_from_specified( const mbedtls_asn1_buf *params, mbedtls_ecp_group *grp ) { int ret; unsigned char *p = params->p; const unsigned char * const end = params->p + params->len; const unsigned char *end_field, *end_curve; size_t len; int ver; /* SpecifiedECDomainVersion ::= INTEGER { 1, 2, 3 } */ if( ( ret = mbedtls_asn1_get_int( &p, end, &ver ) ) != 0 ) return( MBEDTLS_ERR_PK_KEY_INVALID_FORMAT + ret ); if( ver < 1 || ver > 3 ) return( MBEDTLS_ERR_PK_KEY_INVALID_FORMAT ); /* * FieldID { FIELD-ID:IOSet } ::= SEQUENCE { -- Finite field * fieldType FIELD-ID.&id({IOSet}), * parameters FIELD-ID.&Type({IOSet}{@fieldType}) * } */ if( ( ret = mbedtls_asn1_get_tag( &p, end, &len, MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE ) ) != 0 ) return( ret ); end_field = p + len; /* * FIELD-ID ::= TYPE-IDENTIFIER * FieldTypes FIELD-ID ::= { * { Prime-p IDENTIFIED BY prime-field } | * { Characteristic-two IDENTIFIED BY characteristic-two-field } * } * prime-field OBJECT IDENTIFIER ::= { id-fieldType 1 } */ if( ( ret = mbedtls_asn1_get_tag( &p, end_field, &len, MBEDTLS_ASN1_OID ) ) != 0 ) return( ret ); if( len != MBEDTLS_OID_SIZE( MBEDTLS_OID_ANSI_X9_62_PRIME_FIELD ) || memcmp( p, MBEDTLS_OID_ANSI_X9_62_PRIME_FIELD, len ) != 0 ) { return( MBEDTLS_ERR_PK_FEATURE_UNAVAILABLE ); } p += len; /* Prime-p ::= INTEGER -- Field of size p. */ if( ( ret = mbedtls_asn1_get_mpi( &p, end_field, &grp->P ) ) != 0 ) return( MBEDTLS_ERR_PK_KEY_INVALID_FORMAT + ret ); grp->pbits = mbedtls_mpi_bitlen( &grp->P ); if( p != end_field ) return( MBEDTLS_ERR_PK_KEY_INVALID_FORMAT + MBEDTLS_ERR_ASN1_LENGTH_MISMATCH ); /* * Curve ::= SEQUENCE { * a FieldElement, * b FieldElement, * seed BIT STRING OPTIONAL * -- Shall be present if used in SpecifiedECDomain * -- with version equal to ecdpVer2 or ecdpVer3 * } */ if( ( ret = mbedtls_asn1_get_tag( &p, end, &len, MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE ) ) != 0 ) return( ret ); end_curve = p + len; /* * FieldElement ::= OCTET STRING * containing an integer in the case of a prime field */ if( ( ret = mbedtls_asn1_get_tag( &p, end_curve, &len, MBEDTLS_ASN1_OCTET_STRING ) ) != 0 || ( ret = mbedtls_mpi_read_binary( &grp->A, p, len ) ) != 0 ) { return( MBEDTLS_ERR_PK_KEY_INVALID_FORMAT + ret ); } p += len; if( ( ret = mbedtls_asn1_get_tag( &p, end_curve, &len, MBEDTLS_ASN1_OCTET_STRING ) ) != 0 || ( ret = mbedtls_mpi_read_binary( &grp->B, p, len ) ) != 0 ) { return( MBEDTLS_ERR_PK_KEY_INVALID_FORMAT + ret ); } p += len; /* Ignore seed BIT STRING OPTIONAL */ if( ( ret = mbedtls_asn1_get_tag( &p, end_curve, &len, MBEDTLS_ASN1_BIT_STRING ) ) == 0 ) p += len; if( p != end_curve ) return( MBEDTLS_ERR_PK_KEY_INVALID_FORMAT + MBEDTLS_ERR_ASN1_LENGTH_MISMATCH ); /* * ECPoint ::= OCTET STRING */ if( ( ret = mbedtls_asn1_get_tag( &p, end, &len, MBEDTLS_ASN1_OCTET_STRING ) ) != 0 ) return( MBEDTLS_ERR_PK_KEY_INVALID_FORMAT + ret ); if( ( ret = mbedtls_ecp_point_read_binary( grp, &grp->G, ( const unsigned char *) p, len ) ) != 0 ) { /* * If we can't read the point because it's compressed, cheat by * reading only the X coordinate and the parity bit of Y. */ if( ret != MBEDTLS_ERR_ECP_FEATURE_UNAVAILABLE || ( p[0] != 0x02 && p[0] != 0x03 ) || len != mbedtls_mpi_size( &grp->P ) + 1 || mbedtls_mpi_read_binary( &grp->G.X, p + 1, len - 1 ) != 0 || mbedtls_mpi_lset( &grp->G.Y, p[0] - 2 ) != 0 || mbedtls_mpi_lset( &grp->G.Z, 1 ) != 0 ) { return( MBEDTLS_ERR_PK_KEY_INVALID_FORMAT ); } } p += len; /* * order INTEGER */ if( ( ret = mbedtls_asn1_get_mpi( &p, end, &grp->N ) ) != 0 ) return( MBEDTLS_ERR_PK_KEY_INVALID_FORMAT + ret ); grp->nbits = mbedtls_mpi_bitlen( &grp->N ); /* * Allow optional elements by purposefully not enforcing p == end here. */ return( 0 ); }
int mbedtls_ecdsa_genkey( mbedtls_ecdsa_context *ctx, mbedtls_ecp_group_id gid, int (*f_rng)(void *, unsigned char *, size_t), void *p_rng ) { int ret = 0; CRYSError_t CrysRet = CRYS_OK; void* pHeap = NULL; size_t heapSize = 0; uint32_t key_size = 2*MAX_KEY_SIZE_IN_BYTES + 1; const CRYS_ECPKI_Domain_t* pDomain = CRYS_ECPKI_GetEcDomain ( convert_mbedtls_grp_id_to_crys_domain_id( gid ) ); mbedtls_rand_func_container cc_rand = { f_rng, p_rng }; if ( pDomain ) { uint8_t temp_buf[ 2 * MAX_KEY_SIZE_IN_BYTES + 1 ] = {0}; cc_ecc_ws_keygen_params_t* kgParams = mbedtls_calloc( 1, sizeof(cc_ecc_ws_keygen_params_t) ); if ( kgParams == NULL ) return ( MBEDTLS_ERR_ECP_ALLOC_FAILED ); pHeap = kgParams; heapSize = sizeof(cc_ecc_ws_keygen_params_t); CrysRet = CRYS_ECPKI_GenKeyPair( &cc_rand, convert_mbedtls_to_cc_rand, pDomain, &kgParams->privKey, &kgParams->pubKey, &kgParams->kgTempData, NULL ); if ( CrysRet != CRYS_OK ) { ret = convert_CrysError_to_mbedtls_err( CrysRet ); goto cleanup; } MBEDTLS_MPI_CHK( mbedtls_ecp_group_load( &ctx->grp, gid ) ); CrysRet = CRYS_ECPKI_ExportPublKey( &kgParams->pubKey, CRYS_EC_PointUncompressed, temp_buf, &key_size ); if ( CrysRet != CRYS_OK ) { ret = convert_CrysError_to_mbedtls_err( CrysRet ); goto cleanup; } ret = mbedtls_ecp_point_read_binary( &ctx->grp, &ctx->Q, temp_buf, key_size ); if ( ret != 0 ) goto cleanup; memset ( temp_buf, 0 , sizeof(temp_buf) ); CrysRet = CRYS_COMMON_ConvertLswMswWordsToMsbLsbBytes( temp_buf, (ctx->grp.nbits+7)/8, kgParams->privKey.PrivKeyDbBuff, 4*((((ctx->grp.nbits+7)/8)+3)/4) ); if ( CrysRet != CRYS_OK ) { ret = convert_CrysError_to_mbedtls_err( CrysRet ); mbedtls_zeroize( temp_buf, sizeof(temp_buf) ); goto cleanup; } ret = mbedtls_mpi_read_binary( &ctx->d, temp_buf, (ctx->grp.nbits+7)/8 ); mbedtls_zeroize( temp_buf, sizeof(temp_buf) ); if ( ret != 0 ) { goto cleanup; } } else ret = MBEDTLS_ERR_PLATFORM_FEATURE_UNSUPPORTED; cleanup: if ( pHeap ) { mbedtls_zeroize( pHeap, heapSize ); mbedtls_free ( pHeap ); } return ( ret ); }
bool ECKey_From(const cn_cbor * pKey, mbedtls_ecp_keypair *keypair, cose_errback * perr) { byte rgbKey[MBEDTLS_ECP_MAX_PT_LEN]; int cbKey; int cbGroup; const cn_cbor * p; mbedtls_ecp_group_id groupId; p = cn_cbor_mapget_int(pKey, COSE_Key_Type); CHECK_CONDITION(p != NULL, COSE_ERR_INVALID_PARAMETER); if(p->type == CN_CBOR_UINT) { CHECK_CONDITION(p->v.uint == COSE_Key_Type_EC2, COSE_ERR_INVALID_PARAMETER); } else { FAIL_CONDITION(COSE_ERR_INVALID_PARAMETER); } p = cn_cbor_mapget_int(pKey, COSE_Key_EC_Curve); CHECK_CONDITION((p != NULL) && (p->type == CN_CBOR_UINT), COSE_ERR_INVALID_PARAMETER); switch (p->v.uint) { case 1: // P-256 groupId = MBEDTLS_ECP_DP_SECP256R1; break; case 2: // P-384 groupId = MBEDTLS_ECP_DP_SECP384R1; break; case 3: // P-521 groupId = MBEDTLS_ECP_DP_SECP521R1; break; default: FAIL_CONDITION(COSE_ERR_INVALID_PARAMETER); } CHECK_CONDITION(mbedtls_ecp_group_load(&keypair->grp, groupId) == 0, COSE_ERR_INVALID_PARAMETER); cbGroup = (keypair->grp.nbits + 7) / 8; p = cn_cbor_mapget_int(pKey, COSE_Key_EC_X); CHECK_CONDITION((p != NULL) && (p->type == CN_CBOR_BYTES), COSE_ERR_INVALID_PARAMETER); CHECK_CONDITION(p->length == cbGroup, COSE_ERR_INVALID_PARAMETER); memcpy(rgbKey+1, p->v.str, p->length); p = cn_cbor_mapget_int(pKey, COSE_Key_EC_Y); CHECK_CONDITION((p != NULL), COSE_ERR_INVALID_PARAMETER); if (p->type == CN_CBOR_BYTES) { rgbKey[0] = 0x04; cbKey = cbGroup * 2 + 1; CHECK_CONDITION(p->length == cbGroup, COSE_ERR_INVALID_PARAMETER); memcpy(rgbKey + p->length + 1, p->v.str, p->length); } else if (p->type == CN_CBOR_TRUE) { cbKey = cbGroup + 1; rgbKey[0] = 0x03; } else if (p->type == CN_CBOR_FALSE) { cbKey = cbGroup + 1; rgbKey[0] = 0x02; } else FAIL_CONDITION(COSE_ERR_INVALID_PARAMETER); CHECK_CONDITION(mbedtls_ecp_point_read_binary(&keypair->grp, &keypair->Q, rgbKey, cbKey) == 0, COSE_ERR_INVALID_PARAMETER); p = cn_cbor_mapget_int(pKey, COSE_Key_EC_d); if (p != NULL) { CHECK_CONDITION(p->type == CN_CBOR_BYTES, COSE_ERR_INVALID_PARAMETER); CHECK_CONDITION(mbedtls_mpi_read_binary( &keypair->d, p->v.bytes, p->length) == 0, COSE_ERR_CRYPTO_FAIL); } return true; errorReturn: return false; }
int mbedtls_ecdh_gen_public( mbedtls_ecp_group *grp, mbedtls_mpi *d, mbedtls_ecp_point *Q, int ( *f_rng )( void *, unsigned char *, size_t ), void *p_rng ) { int ret = 0; void* pHeap = NULL; size_t heapSize = 0; uint32_t public_key_size = (2 * MAX_KEY_SIZE_IN_BYTES + 1); const CRYS_ECPKI_Domain_t* pDomain = CRYS_ECPKI_GetEcDomain ( convert_mbedtls_grp_id_to_crys_domain_id( grp->id ) ); mbedtls_rand_func_container cc_rand = { f_rng, p_rng }; if ( pDomain ) { uint8_t temp_buf[ 2 * MAX_KEY_SIZE_IN_BYTES + 1 ] = {0}; cc_ecc_ws_keygen_params_t* kgParams = mbedtls_calloc( 1, sizeof( cc_ecc_ws_keygen_params_t ) ); if ( kgParams == NULL ) return ( MBEDTLS_ERR_ECP_ALLOC_FAILED ); pHeap = kgParams; heapSize = sizeof( cc_ecc_ws_keygen_params_t ); ret = convert_CrysError_to_mbedtls_err( CRYS_ECPKI_GenKeyPair( &cc_rand, convert_mbedtls_to_cc_rand, pDomain, &kgParams->privKey, &kgParams->pubKey, &kgParams->kgTempData, NULL ) ); if( ret != 0 ) { goto cleanup; } ret = convert_CrysError_to_mbedtls_err( CRYS_ECPKI_ExportPublKey( &kgParams->pubKey, CRYS_EC_PointUncompressed,temp_buf, &public_key_size ) ); if( ret != 0 ) { goto cleanup; } MBEDTLS_MPI_CHK( mbedtls_ecp_point_read_binary( grp, Q, temp_buf, public_key_size ) ); memset ( temp_buf, 0 , sizeof(temp_buf) ); ret = convert_CrysError_to_mbedtls_err( CRYS_COMMON_ConvertLswMswWordsToMsbLsbBytes( temp_buf, (grp->nbits+7)/8, kgParams->privKey.PrivKeyDbBuff, 4*((((grp->nbits+7)/8)+3)/4) ) ); if( ret != 0 ) { mbedtls_zeroize( temp_buf, sizeof( temp_buf ) ); goto cleanup; } MBEDTLS_MPI_CHK(mbedtls_mpi_read_binary( d, temp_buf, (grp->nbits+7)/8 ) ); mbedtls_zeroize( temp_buf, sizeof( temp_buf ) ); } /* if CRYS_ECPKI_GetEcDomain returns NULL, then the given curve is either Montgomery 25519 * or another curve which is not supported by CC310*/ else if ( grp->id == MBEDTLS_ECP_DP_CURVE25519 ) { size_t priv_key_size = public_key_size = CURVE_25519_KEY_SIZE ; cc_ecc_25519_keygen_params_t* kgParams = mbedtls_calloc( 1, sizeof(cc_ecc_25519_keygen_params_t) ); if ( kgParams == NULL ) return ( MBEDTLS_ERR_ECP_ALLOC_FAILED ); pHeap = ( uint8_t* )kgParams; heapSize = sizeof(cc_ecc_25519_keygen_params_t); ret = convert_CrysError_to_mbedtls_err( CRYS_ECMONT_KeyPair( kgParams->pubKey, ( size_t* )&public_key_size, kgParams->privKey, &priv_key_size, &cc_rand, convert_mbedtls_to_cc_rand, &kgParams->kgTempData ) ); if( ret != 0 ) { goto cleanup; } MBEDTLS_MPI_CHK( mbedtls_mpi_read_binary( d, kgParams->privKey, priv_key_size ) ); MBEDTLS_MPI_CHK( mbedtls_mpi_read_binary( &Q->X, kgParams->pubKey, public_key_size ) ); MBEDTLS_MPI_CHK( mbedtls_mpi_lset( &Q->Z, 1 ) ); } else ret = MBEDTLS_ERR_PLATFORM_FEATURE_UNSUPPORTED; cleanup: if ( pHeap ) { mbedtls_zeroize( pHeap, heapSize ); mbedtls_free( pHeap ); } return ( ret ); }