/* * RSAPublicKey ::= SEQUENCE { * modulus INTEGER, -- n * publicExponent INTEGER -- e * } */ static int pk_get_rsapubkey( unsigned char **p, const unsigned char *end, mbedtls_rsa_context *rsa ) { int ret; size_t len; if( ( ret = mbedtls_asn1_get_tag( p, end, &len, MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE ) ) != 0 ) return( MBEDTLS_ERR_PK_INVALID_PUBKEY + ret ); if( *p + len != end ) return( MBEDTLS_ERR_PK_INVALID_PUBKEY + MBEDTLS_ERR_ASN1_LENGTH_MISMATCH ); if( ( ret = mbedtls_asn1_get_mpi( p, end, &rsa->N ) ) != 0 || ( ret = mbedtls_asn1_get_mpi( p, end, &rsa->E ) ) != 0 ) return( MBEDTLS_ERR_PK_INVALID_PUBKEY + ret ); if( *p != end ) return( MBEDTLS_ERR_PK_INVALID_PUBKEY + MBEDTLS_ERR_ASN1_LENGTH_MISMATCH ); if( ( ret = mbedtls_rsa_check_pubkey( rsa ) ) != 0 ) return( MBEDTLS_ERR_PK_INVALID_PUBKEY ); rsa->len = mbedtls_mpi_size( &rsa->N ); return( 0 ); }
/* * Restartable read and check signature */ int mbedtls_ecdsa_read_signature_restartable( mbedtls_ecdsa_context *ctx, const unsigned char *hash, size_t hlen, const unsigned char *sig, size_t slen, mbedtls_ecdsa_restart_ctx *rs_ctx ) { int ret; unsigned char *p = (unsigned char *) sig; const unsigned char *end = sig + slen; size_t len; mbedtls_mpi r, s; mbedtls_mpi_init( &r ); mbedtls_mpi_init( &s ); if( ( ret = mbedtls_asn1_get_tag( &p, end, &len, MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE ) ) != 0 ) { ret += MBEDTLS_ERR_ECP_BAD_INPUT_DATA; goto cleanup; } if( p + len != end ) { ret = MBEDTLS_ERR_ECP_BAD_INPUT_DATA + MBEDTLS_ERR_ASN1_LENGTH_MISMATCH; goto cleanup; } if( ( ret = mbedtls_asn1_get_mpi( &p, end, &r ) ) != 0 || ( ret = mbedtls_asn1_get_mpi( &p, end, &s ) ) != 0 ) { ret += MBEDTLS_ERR_ECP_BAD_INPUT_DATA; goto cleanup; } #if defined(MBEDTLS_ECDSA_VERIFY_ALT) if( ( ret = mbedtls_ecdsa_verify( &ctx->grp, hash, hlen, &ctx->Q, &r, &s ) ) != 0 ) goto cleanup; #else if( ( ret = ecdsa_verify_restartable( &ctx->grp, hash, hlen, &ctx->Q, &r, &s, rs_ctx ) ) != 0 ) goto cleanup; #endif /* MBEDTLS_ECDSA_VERIFY_ALT */ /* At this point we know that the buffer starts with a valid signature. * Return 0 if the buffer just contains the signature, and a specific * error code if the valid signature is followed by more data. */ if( p != end ) ret = MBEDTLS_ERR_ECP_SIG_LEN_MISMATCH; cleanup: mbedtls_mpi_free( &r ); mbedtls_mpi_free( &s ); return( ret ); }
/* * Read and check signature */ int mbedtls_ecdsa_read_signature( mbedtls_ecdsa_context *ctx, const unsigned char *hash, size_t hlen, const unsigned char *sig, size_t slen ) { int ret; unsigned char *p = (unsigned char *) sig; const unsigned char *end = sig + slen; size_t len; mbedtls_mpi r, s; mbedtls_mpi_init( &r ); mbedtls_mpi_init( &s ); if( ( ret = mbedtls_asn1_get_tag( &p, end, &len, MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE ) ) != 0 ) { ret += MBEDTLS_ERR_ECP_BAD_INPUT_DATA; goto cleanup; } if( p + len != end ) { ret = MBEDTLS_ERR_ECP_BAD_INPUT_DATA + MBEDTLS_ERR_ASN1_LENGTH_MISMATCH; goto cleanup; } if( ( ret = mbedtls_asn1_get_mpi( &p, end, &r ) ) != 0 || ( ret = mbedtls_asn1_get_mpi( &p, end, &s ) ) != 0 ) { ret += MBEDTLS_ERR_ECP_BAD_INPUT_DATA; goto cleanup; } if( ( ret = mbedtls_ecdsa_verify( &ctx->grp, hash, hlen, &ctx->Q, &r, &s ) ) != 0 ) goto cleanup; if( p != end ) ret = MBEDTLS_ERR_ECP_SIG_LEN_MISMATCH; cleanup: mbedtls_mpi_free( &r ); mbedtls_mpi_free( &s ); return( ret ); }
/* * Parse a PKCS#1 encoded private RSA key */ static int pk_parse_key_pkcs1_der( mbedtls_rsa_context *rsa, const unsigned char *key, size_t keylen ) { int ret; size_t len; unsigned char *p, *end; p = (unsigned char *) key; end = p + keylen; /* * This function parses the RSAPrivateKey (PKCS#1) * * RSAPrivateKey ::= SEQUENCE { * version Version, * modulus INTEGER, -- n * publicExponent INTEGER, -- e * privateExponent INTEGER, -- d * prime1 INTEGER, -- p * prime2 INTEGER, -- q * exponent1 INTEGER, -- d mod (p-1) * exponent2 INTEGER, -- d mod (q-1) * coefficient INTEGER, -- (inverse of q) mod p * otherPrimeInfos OtherPrimeInfos OPTIONAL * } */ if( ( ret = mbedtls_asn1_get_tag( &p, end, &len, MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE ) ) != 0 ) { return( MBEDTLS_ERR_PK_KEY_INVALID_FORMAT + ret ); } end = p + len; if( ( ret = mbedtls_asn1_get_int( &p, end, &rsa->ver ) ) != 0 ) { return( MBEDTLS_ERR_PK_KEY_INVALID_FORMAT + ret ); } if( rsa->ver != 0 ) { return( MBEDTLS_ERR_PK_KEY_INVALID_VERSION ); } if( ( ret = mbedtls_asn1_get_mpi( &p, end, &rsa->N ) ) != 0 || ( ret = mbedtls_asn1_get_mpi( &p, end, &rsa->E ) ) != 0 || ( ret = mbedtls_asn1_get_mpi( &p, end, &rsa->D ) ) != 0 || ( ret = mbedtls_asn1_get_mpi( &p, end, &rsa->P ) ) != 0 || ( ret = mbedtls_asn1_get_mpi( &p, end, &rsa->Q ) ) != 0 || ( ret = mbedtls_asn1_get_mpi( &p, end, &rsa->DP ) ) != 0 || ( ret = mbedtls_asn1_get_mpi( &p, end, &rsa->DQ ) ) != 0 || ( ret = mbedtls_asn1_get_mpi( &p, end, &rsa->QP ) ) != 0 ) { mbedtls_rsa_free( rsa ); return( MBEDTLS_ERR_PK_KEY_INVALID_FORMAT + ret ); } rsa->len = mbedtls_mpi_size( &rsa->N ); if( p != end ) { mbedtls_rsa_free( rsa ); return( MBEDTLS_ERR_PK_KEY_INVALID_FORMAT + MBEDTLS_ERR_ASN1_LENGTH_MISMATCH ); } if( ( ret = mbedtls_rsa_check_privkey( rsa ) ) != 0 ) { mbedtls_rsa_free( rsa ); return( ret ); } return( 0 ); }
/* * 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 ); }
/* * Parse DHM parameters */ int mbedtls_dhm_parse_dhm( mbedtls_dhm_context *dhm, const unsigned char *dhmin, size_t dhminlen ) { int ret; size_t len; unsigned char *p, *end; #if defined(MBEDTLS_PEM_PARSE_C) mbedtls_pem_context pem; mbedtls_pem_init( &pem ); /* Avoid calling mbedtls_pem_read_buffer() on non-null-terminated string */ if( dhminlen == 0 || dhmin[dhminlen - 1] != '\0' ) ret = MBEDTLS_ERR_PEM_NO_HEADER_FOOTER_PRESENT; else ret = mbedtls_pem_read_buffer( &pem, "-----BEGIN DH PARAMETERS-----", "-----END DH PARAMETERS-----", dhmin, NULL, 0, &dhminlen ); if( ret == 0 ) { /* * Was PEM encoded */ dhminlen = pem.buflen; } else if( ret != MBEDTLS_ERR_PEM_NO_HEADER_FOOTER_PRESENT ) goto exit; p = ( ret == 0 ) ? pem.buf : (unsigned char *) dhmin; #else p = (unsigned char *) dhmin; #endif /* MBEDTLS_PEM_PARSE_C */ end = p + dhminlen; /* * DHParams ::= SEQUENCE { * prime INTEGER, -- P * generator INTEGER, -- g * privateValueLength INTEGER OPTIONAL * } */ if( ( ret = mbedtls_asn1_get_tag( &p, end, &len, MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE ) ) != 0 ) { ret = MBEDTLS_ERR_DHM_INVALID_FORMAT + ret; goto exit; } end = p + len; if( ( ret = mbedtls_asn1_get_mpi( &p, end, &dhm->P ) ) != 0 || ( ret = mbedtls_asn1_get_mpi( &p, end, &dhm->G ) ) != 0 ) { ret = MBEDTLS_ERR_DHM_INVALID_FORMAT + ret; goto exit; } if( p != end ) { /* This might be the optional privateValueLength. * If so, we can cleanly discard it */ mbedtls_mpi rec; mbedtls_mpi_init( &rec ); ret = mbedtls_asn1_get_mpi( &p, end, &rec ); mbedtls_mpi_free( &rec ); if ( ret != 0 ) { ret = MBEDTLS_ERR_DHM_INVALID_FORMAT + ret; goto exit; } if ( p != end ) { ret = MBEDTLS_ERR_DHM_INVALID_FORMAT + MBEDTLS_ERR_ASN1_LENGTH_MISMATCH; goto exit; } } ret = 0; dhm->len = mbedtls_mpi_size( &dhm->P ); exit: #if defined(MBEDTLS_PEM_PARSE_C) mbedtls_pem_free( &pem ); #endif if( ret != 0 ) mbedtls_dhm_free( dhm ); return( ret ); }