/* * Do an RSA public key operation */ int shrsa_public( shrsa_context *ctx, const unsigned char *input, unsigned char *output ) { int ret; size_t olen; shmpi T; shmpi_init( &T ); MPI_CHK( shmpi_read_binary( &T, input, ctx->len ) ); if( shmpi_cmp_shmpi( &T, &ctx->N ) >= 0 ) { shmpi_free( &T ); return( RSA_ERR_RSA_BAD_INPUT_DATA ); } #if defined(RSA_THREADING_C) polarssl_mutex_lock( &ctx->mutex ); #endif olen = ctx->len; MPI_CHK( shmpi_exp_mod( &T, &T, &ctx->E, &ctx->N, &ctx->RN ) ); MPI_CHK( shmpi_write_binary( &T, output, olen ) ); cleanup: #if defined(RSA_THREADING_C) polarssl_mutex_unlock( &ctx->mutex ); #endif shmpi_free( &T ); if( ret != 0 ) return( RSA_ERR_RSA_PUBLIC_FAILED + ret ); return( 0 ); }
/* * Parse a SEC1 encoded private EC key */ static int pk_parse_key_sec1_der( ecp_keypair *eck, const unsigned char *key, size_t keylen ) { int ret; int version, pubkey_done; size_t len; asn1_buf params; unsigned char *p = (unsigned char *) key; unsigned char *end = p + keylen; unsigned char *end2; /* * RFC 5915, or SEC1 Appendix C.4 * * ECPrivateKey ::= SEQUENCE { * version INTEGER { ecPrivkeyVer1(1) } (ecPrivkeyVer1), * privateKey OCTET STRING, * parameters [0] ECParameters {{ NamedCurve }} OPTIONAL, * publicKey [1] BIT STRING OPTIONAL * } */ if( ( ret = asn1_get_tag( &p, end, &len, ASN1_CONSTRUCTED | ASN1_SEQUENCE ) ) != 0 ) { return( POLARSSL_ERR_PK_KEY_INVALID_FORMAT + ret ); } end = p + len; if( ( ret = asn1_get_int( &p, end, &version ) ) != 0 ) return( POLARSSL_ERR_PK_KEY_INVALID_FORMAT + ret ); if( version != 1 ) return( POLARSSL_ERR_PK_KEY_INVALID_VERSION ); if( ( ret = asn1_get_tag( &p, end, &len, ASN1_OCTET_STRING ) ) != 0 ) return( POLARSSL_ERR_PK_KEY_INVALID_FORMAT + ret ); if( ( ret = shmpi_read_binary( &eck->d, p, len ) ) != 0 ) { ecp_keypair_free( eck ); return( POLARSSL_ERR_PK_KEY_INVALID_FORMAT + ret ); } p += len; pubkey_done = 0; if( p != end ) { /* * Is 'parameters' present? */ if( ( ret = asn1_get_tag( &p, end, &len, ASN1_CONTEXT_SPECIFIC | ASN1_CONSTRUCTED | 0 ) ) == 0 ) { if( ( ret = pk_get_ecparams( &p, p + len, ¶ms) ) != 0 || ( ret = pk_use_ecparams( ¶ms, &eck->grp ) ) != 0 ) { ecp_keypair_free( eck ); return( ret ); } } else if( ret != POLARSSL_ERR_ASN1_UNEXPECTED_TAG ) { ecp_keypair_free( eck ); return( POLARSSL_ERR_PK_KEY_INVALID_FORMAT + ret ); } /* * Is 'publickey' present? If not, or if we can't read it (eg because it * is compressed), create it from the private key. */ if( ( ret = asn1_get_tag( &p, end, &len, ASN1_CONTEXT_SPECIFIC | ASN1_CONSTRUCTED | 1 ) ) == 0 ) { end2 = p + len; if( ( ret = asn1_get_bitstring_null( &p, end2, &len ) ) != 0 ) return( POLARSSL_ERR_PK_KEY_INVALID_FORMAT + ret ); if( p + len != end2 ) return( POLARSSL_ERR_PK_KEY_INVALID_FORMAT + POLARSSL_ERR_ASN1_LENGTH_MISMATCH ); if( ( ret = pk_get_ecpubkey( &p, end2, eck ) ) == 0 ) pubkey_done = 1; else { /* * The only acceptable failure mode of pk_get_ecpubkey() above * is if the point format is not recognized. */ if( ret != POLARSSL_ERR_ECP_FEATURE_UNAVAILABLE ) return( POLARSSL_ERR_PK_KEY_INVALID_FORMAT ); } } else if( ret != POLARSSL_ERR_ASN1_UNEXPECTED_TAG ) { ecp_keypair_free( eck ); return( POLARSSL_ERR_PK_KEY_INVALID_FORMAT + ret ); } } if( ! pubkey_done && ( ret = ecp_mul( &eck->grp, &eck->Q, &eck->d, &eck->grp.G, NULL, NULL ) ) != 0 ) { ecp_keypair_free( eck ); return( POLARSSL_ERR_PK_KEY_INVALID_FORMAT + ret ); } if( ( ret = ecp_check_privkey( &eck->grp, &eck->d ) ) != 0 ) { ecp_keypair_free( eck ); 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 asn1_buf *params, 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 = asn1_get_int( &p, end, &ver ) ) != 0 ) return( POLARSSL_ERR_PK_KEY_INVALID_FORMAT + ret ); if( ver < 1 || ver > 3 ) return( POLARSSL_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 = asn1_get_tag( &p, end, &len, ASN1_CONSTRUCTED | 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 = asn1_get_tag( &p, end_field, &len, ASN1_OID ) ) != 0 ) return( ret ); if( len != OID_SIZE( OID_ANSI_X9_62_PRIME_FIELD ) || memcmp( p, OID_ANSI_X9_62_PRIME_FIELD, len ) != 0 ) { return( POLARSSL_ERR_PK_FEATURE_UNAVAILABLE ); } p += len; /* Prime-p ::= INTEGER -- Field of size p. */ if( ( ret = asn1_get_shmpi( &p, end_field, &grp->P ) ) != 0 ) return( POLARSSL_ERR_PK_KEY_INVALID_FORMAT + ret ); grp->pbits = shmpi_msb( &grp->P ); if( p != end_field ) return( POLARSSL_ERR_PK_KEY_INVALID_FORMAT + POLARSSL_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 = asn1_get_tag( &p, end, &len, ASN1_CONSTRUCTED | ASN1_SEQUENCE ) ) != 0 ) return( ret ); end_curve = p + len; /* * FieldElement ::= OCTET STRING * containing an integer in the case of a prime field */ if( ( ret = asn1_get_tag( &p, end_curve, &len, ASN1_OCTET_STRING ) ) != 0 || ( ret = shmpi_read_binary( &grp->A, p, len ) ) != 0 ) { return( POLARSSL_ERR_PK_KEY_INVALID_FORMAT + ret ); } p += len; if( ( ret = asn1_get_tag( &p, end_curve, &len, ASN1_OCTET_STRING ) ) != 0 || ( ret = shmpi_read_binary( &grp->B, p, len ) ) != 0 ) { return( POLARSSL_ERR_PK_KEY_INVALID_FORMAT + ret ); } p += len; /* Ignore seed BIT STRING OPTIONAL */ if( ( ret = asn1_get_tag( &p, end_curve, &len, ASN1_BIT_STRING ) ) == 0 ) p += len; if( p != end_curve ) return( POLARSSL_ERR_PK_KEY_INVALID_FORMAT + POLARSSL_ERR_ASN1_LENGTH_MISMATCH ); /* * ECPoint ::= OCTET STRING */ if( ( ret = asn1_get_tag( &p, end, &len, ASN1_OCTET_STRING ) ) != 0 ) return( POLARSSL_ERR_PK_KEY_INVALID_FORMAT + ret ); if( ( ret = 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 != POLARSSL_ERR_ECP_FEATURE_UNAVAILABLE || ( p[0] != 0x02 && p[0] != 0x03 ) || len != shmpi_size( &grp->P ) + 1 || shmpi_read_binary( &grp->G.X, p + 1, len - 1 ) != 0 || shmpi_lset( &grp->G.Y, p[0] - 2 ) != 0 || shmpi_lset( &grp->G.Z, 1 ) != 0 ) { return( POLARSSL_ERR_PK_KEY_INVALID_FORMAT ); } } p += len; /* * order INTEGER */ if( ( ret = asn1_get_shmpi( &p, end, &grp->N ) ) != 0 ) return( POLARSSL_ERR_PK_KEY_INVALID_FORMAT + ret ); grp->nbits = shmpi_msb( &grp->N ); /* * Allow optional elements by purposefully not enforcing p == end here. */ return( 0 ); }
/* * Do an RSA private key operation */ int shrsa_private( shrsa_context *ctx, int (*f_rng)(void *, unsigned char *, size_t), void *p_rng, const unsigned char *input, unsigned char *output ) { int ret; size_t olen; shmpi T, T1, T2; shmpi *Vi, *Vf; /* * When using the Chinese Remainder Theorem, we use blinding values. * Without threading, we just read them directly from the context, * otherwise we make a local copy in order to reduce locking contention. */ #if defined(RSA_THREADING_C) shmpi Vi_copy, Vf_copy; shmpi_init( &Vi_copy ); shmpi_init( &Vf_copy ); Vi = &Vi_copy; Vf = &Vf_copy; #else Vi = &ctx->Vi; Vf = &ctx->Vf; #endif shmpi_init( &T ); shmpi_init( &T1 ); shmpi_init( &T2 ); MPI_CHK( shmpi_read_binary( &T, input, ctx->len ) ); if( shmpi_cmp_shmpi( &T, &ctx->N ) >= 0 ) { shmpi_free( &T ); return( RSA_ERR_RSA_BAD_INPUT_DATA ); } if( f_rng != NULL ) { /* * Blinding * T = T * Vi mod N */ MPI_CHK( shrsa_prepare_blinding( ctx, Vi, Vf, f_rng, p_rng ) ); MPI_CHK( shmpi_mul_shmpi( &T, &T, Vi ) ); MPI_CHK( shmpi_mod_shmpi( &T, &T, &ctx->N ) ); } #if defined(RSA_THREADING_C) polarssl_mutex_lock( &ctx->mutex ); #endif #if defined(RSA_RSA_NO_CRT) MPI_CHK( shmpi_exp_mod( &T, &T, &ctx->D, &ctx->N, &ctx->RN ) ); #else /* * faster decryption using the CRT * * T1 = input ^ dP mod P * T2 = input ^ dQ mod Q */ MPI_CHK( shmpi_exp_mod( &T1, &T, &ctx->DP, &ctx->P, &ctx->RP ) ); MPI_CHK( shmpi_exp_mod( &T2, &T, &ctx->DQ, &ctx->Q, &ctx->RQ ) ); /* * T = (T1 - T2) * (Q^-1 mod P) mod P */ MPI_CHK( shmpi_sub_shmpi( &T, &T1, &T2 ) ); MPI_CHK( shmpi_mul_shmpi( &T1, &T, &ctx->QP ) ); MPI_CHK( shmpi_mod_shmpi( &T, &T1, &ctx->P ) ); /* * T = T2 + T * Q */ MPI_CHK( shmpi_mul_shmpi( &T1, &T, &ctx->Q ) ); MPI_CHK( shmpi_add_shmpi( &T, &T2, &T1 ) ); #endif /* RSA_RSA_NO_CRT */ if( f_rng != NULL ) { /* * Unblind * T = T * Vf mod N */ MPI_CHK( shmpi_mul_shmpi( &T, &T, Vf ) ); MPI_CHK( shmpi_mod_shmpi( &T, &T, &ctx->N ) ); } olen = ctx->len; MPI_CHK( shmpi_write_binary( &T, output, olen ) ); cleanup: #if defined(RSA_THREADING_C) polarssl_mutex_unlock( &ctx->mutex ); shmpi_free( &Vi_copy ); shmpi_free( &Vf_copy ); #endif shmpi_free( &T ); shmpi_free( &T1 ); shmpi_free( &T2 ); if( ret != 0 ) return( RSA_ERR_RSA_PRIVATE_FAILED + ret ); return( 0 ); }