/* * Check a public RSA key */ int shrsa_check_pubkey( const shrsa_context *ctx ) { if( !ctx->N.p || !ctx->E.p ) return( RSA_ERR_RSA_KEY_CHECK_FAILED ); if( ( ctx->N.p[0] & 1 ) == 0 || ( ctx->E.p[0] & 1 ) == 0 ) return( RSA_ERR_RSA_KEY_CHECK_FAILED ); if( shmpi_msb( &ctx->N ) < 128 || shmpi_msb( &ctx->N ) > MPI_MPI_MAX_BITS ) return( RSA_ERR_RSA_KEY_CHECK_FAILED ); if( shmpi_msb( &ctx->E ) < 2 || shmpi_cmp_shmpi( &ctx->E, &ctx->N ) >= 0 ) return( RSA_ERR_RSA_KEY_CHECK_FAILED ); 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 ); }
/* * Generate an RSA keypair */ int shrsa_gen_key( shrsa_context *ctx, int (*f_rng)(void *, unsigned char *, size_t), void *p_rng, unsigned int nbits, int exponent ) { int ret; shmpi P1, Q1, H, G; if( f_rng == NULL || nbits < 128 || exponent < 3 ) return( RSA_ERR_RSA_BAD_INPUT_DATA ); shmpi_init( &P1 ); shmpi_init( &Q1 ); shmpi_init( &H ); shmpi_init( &G ); /* * find primes P and Q with Q < P so that: * GCD( E, (P-1)*(Q-1) ) == 1 */ MPI_CHK( shmpi_lset( &ctx->E, exponent ) ); do { MPI_CHK( shmpi_gen_prime( &ctx->P, ( nbits + 1 ) >> 1, 0, f_rng, p_rng ) ); MPI_CHK( shmpi_gen_prime( &ctx->Q, ( nbits + 1 ) >> 1, 0, f_rng, p_rng ) ); if( shmpi_cmp_shmpi( &ctx->P, &ctx->Q ) < 0 ) shmpi_swap( &ctx->P, &ctx->Q ); if( shmpi_cmp_shmpi( &ctx->P, &ctx->Q ) == 0 ) continue; MPI_CHK( shmpi_mul_shmpi( &ctx->N, &ctx->P, &ctx->Q ) ); if( shmpi_msb( &ctx->N ) != nbits ) continue; MPI_CHK( shmpi_sub_int( &P1, &ctx->P, 1 ) ); MPI_CHK( shmpi_sub_int( &Q1, &ctx->Q, 1 ) ); MPI_CHK( shmpi_mul_shmpi( &H, &P1, &Q1 ) ); MPI_CHK( shmpi_gcd( &G, &ctx->E, &H ) ); } while( shmpi_cmp_int( &G, 1 ) != 0 ); /* * D = E^-1 mod ((P-1)*(Q-1)) * DP = D mod (P - 1) * DQ = D mod (Q - 1) * QP = Q^-1 mod P */ MPI_CHK( shmpi_inv_mod( &ctx->D , &ctx->E, &H ) ); MPI_CHK( shmpi_mod_shmpi( &ctx->DP, &ctx->D, &P1 ) ); MPI_CHK( shmpi_mod_shmpi( &ctx->DQ, &ctx->D, &Q1 ) ); MPI_CHK( shmpi_inv_mod( &ctx->QP, &ctx->Q, &ctx->P ) ); ctx->len = ( shmpi_msb( &ctx->N ) + 7 ) >> 3; cleanup: shmpi_free( &P1 ); shmpi_free( &Q1 ); shmpi_free( &H ); shmpi_free( &G ); if( ret != 0 ) { shrsa_free( ctx ); return( RSA_ERR_RSA_KEY_GEN_FAILED + ret ); } return( 0 ); }