/* * RSASSA-PSS-params ::= SEQUENCE { * hashAlgorithm [0] HashAlgorithm DEFAULT sha1Identifier, * maskGenAlgorithm [1] MaskGenAlgorithm DEFAULT mgf1SHA1Identifier, * saltLength [2] INTEGER DEFAULT 20, * trailerField [3] INTEGER DEFAULT 1 } * -- Note that the tags in this Sequence are explicit. * * RFC 4055 (which defines use of RSASSA-PSS in PKIX) states that the value * of trailerField MUST be 1, and PKCS#1 v2.2 doesn't even define any other * option. Enfore this at parsing time. */ int x509_get_rsassa_pss_params( const x509_buf *params, md_type_t *md_alg, md_type_t *mgf_md, int *salt_len ) { int ret; unsigned char *p; const unsigned char *end, *end2; size_t len; x509_buf alg_id, alg_params; /* First set everything to defaults */ *md_alg = POLARSSL_MD_SHA1; *mgf_md = POLARSSL_MD_SHA1; *salt_len = 20; /* Make sure params is a SEQUENCE and setup bounds */ if( params->tag != ( ASN1_CONSTRUCTED | ASN1_SEQUENCE ) ) return( POLARSSL_ERR_X509_INVALID_ALG + POLARSSL_ERR_ASN1_UNEXPECTED_TAG ); p = (unsigned char *) params->p; end = p + params->len; if( p == end ) return( 0 ); /* * HashAlgorithm */ if( ( ret = asn1_get_tag( &p, end, &len, ASN1_CONTEXT_SPECIFIC | ASN1_CONSTRUCTED | 0 ) ) == 0 ) { end2 = p + len; /* HashAlgorithm ::= AlgorithmIdentifier (without parameters) */ if( ( ret = x509_get_alg_null( &p, end2, &alg_id ) ) != 0 ) return( ret ); if( ( ret = oid_get_md_alg( &alg_id, md_alg ) ) != 0 ) return( POLARSSL_ERR_X509_INVALID_ALG + ret ); if( p != end2 ) return( POLARSSL_ERR_X509_INVALID_ALG + POLARSSL_ERR_ASN1_LENGTH_MISMATCH ); } else if( ret != POLARSSL_ERR_ASN1_UNEXPECTED_TAG ) return( POLARSSL_ERR_X509_INVALID_ALG + ret ); if( p == end ) return( 0 ); /* * MaskGenAlgorithm */ if( ( ret = asn1_get_tag( &p, end, &len, ASN1_CONTEXT_SPECIFIC | ASN1_CONSTRUCTED | 1 ) ) == 0 ) { end2 = p + len; /* MaskGenAlgorithm ::= AlgorithmIdentifier (params = HashAlgorithm) */ if( ( ret = x509_get_alg( &p, end2, &alg_id, &alg_params ) ) != 0 ) return( ret ); /* Only MFG1 is recognised for now */ if( ! OID_CMP( OID_MGF1, &alg_id ) ) return( POLARSSL_ERR_X509_FEATURE_UNAVAILABLE + POLARSSL_ERR_OID_NOT_FOUND ); /* Parse HashAlgorithm */ if( ( ret = x509_get_hash_alg( &alg_params, mgf_md ) ) != 0 ) return( ret ); if( p != end2 ) return( POLARSSL_ERR_X509_INVALID_ALG + POLARSSL_ERR_ASN1_LENGTH_MISMATCH ); } else if( ret != POLARSSL_ERR_ASN1_UNEXPECTED_TAG ) return( POLARSSL_ERR_X509_INVALID_ALG + ret ); if( p == end ) return( 0 ); /* * salt_len */ if( ( ret = asn1_get_tag( &p, end, &len, ASN1_CONTEXT_SPECIFIC | ASN1_CONSTRUCTED | 2 ) ) == 0 ) { end2 = p + len; if( ( ret = asn1_get_int( &p, end2, salt_len ) ) != 0 ) return( POLARSSL_ERR_X509_INVALID_ALG + ret ); if( p != end2 ) return( POLARSSL_ERR_X509_INVALID_ALG + POLARSSL_ERR_ASN1_LENGTH_MISMATCH ); } else if( ret != POLARSSL_ERR_ASN1_UNEXPECTED_TAG ) return( POLARSSL_ERR_X509_INVALID_ALG + ret ); if( p == end ) return( 0 ); /* * trailer_field (if present, must be 1) */ if( ( ret = asn1_get_tag( &p, end, &len, ASN1_CONTEXT_SPECIFIC | ASN1_CONSTRUCTED | 3 ) ) == 0 ) { int trailer_field; end2 = p + len; if( ( ret = asn1_get_int( &p, end2, &trailer_field ) ) != 0 ) return( POLARSSL_ERR_X509_INVALID_ALG + ret ); if( p != end2 ) return( POLARSSL_ERR_X509_INVALID_ALG + POLARSSL_ERR_ASN1_LENGTH_MISMATCH ); if( trailer_field != 1 ) return( POLARSSL_ERR_X509_INVALID_ALG ); } else if( ret != POLARSSL_ERR_ASN1_UNEXPECTED_TAG ) return( POLARSSL_ERR_X509_INVALID_ALG + ret ); if( p != end ) return( POLARSSL_ERR_X509_INVALID_ALG + POLARSSL_ERR_ASN1_LENGTH_MISMATCH ); return( 0 ); }
static int pk_parse_key_pkcs8_encrypted_der( pk_context *pk, const unsigned char *key, size_t keylen, const unsigned char *pwd, size_t pwdlen ) { int ret, decrypted = 0; size_t len; unsigned char buf[2048]; unsigned char *p, *end; asn1_buf pbe_alg_oid, pbe_params; #if defined(POLARSSL_PKCS12_C) cipher_type_t cipher_alg; md_type_t md_alg; #endif memset( buf, 0, sizeof( buf ) ); p = (unsigned char *) key; end = p + keylen; if( pwdlen == 0 ) return( POLARSSL_ERR_PK_PASSWORD_REQUIRED ); /* * This function parses the EncryptedPrivatKeyInfo object (PKCS#8) * * EncryptedPrivateKeyInfo ::= SEQUENCE { * encryptionAlgorithm EncryptionAlgorithmIdentifier, * encryptedData EncryptedData * } * * EncryptionAlgorithmIdentifier ::= AlgorithmIdentifier * * EncryptedData ::= OCTET STRING * * The EncryptedData OCTET STRING is a PKCS#8 PrivateKeyInfo */ 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_alg( &p, end, &pbe_alg_oid, &pbe_params ) ) != 0 ) return( POLARSSL_ERR_PK_KEY_INVALID_FORMAT + ret ); if( ( ret = asn1_get_tag( &p, end, &len, ASN1_OCTET_STRING ) ) != 0 ) return( POLARSSL_ERR_PK_KEY_INVALID_FORMAT + ret ); if( len > sizeof( buf ) ) return( POLARSSL_ERR_PK_BAD_INPUT_DATA ); /* * Decrypt EncryptedData with appropriate PDE */ #if defined(POLARSSL_PKCS12_C) if( oid_get_pkcs12_pbe_alg( &pbe_alg_oid, &md_alg, &cipher_alg ) == 0 ) { if( ( ret = pkcs12_pbe( &pbe_params, PKCS12_PBE_DECRYPT, cipher_alg, md_alg, pwd, pwdlen, p, len, buf ) ) != 0 ) { if( ret == POLARSSL_ERR_PKCS12_PASSWORD_MISMATCH ) return( POLARSSL_ERR_PK_PASSWORD_MISMATCH ); return( ret ); } decrypted = 1; } else if( OID_CMP( OID_PKCS12_PBE_SHA1_RC4_128, &pbe_alg_oid ) ) { if( ( ret = pkcs12_pbe_sha1_rc4_128( &pbe_params, PKCS12_PBE_DECRYPT, pwd, pwdlen, p, len, buf ) ) != 0 ) { return( ret ); } // Best guess for password mismatch when using RC4. If first tag is // not ASN1_CONSTRUCTED | ASN1_SEQUENCE // if( *buf != ( ASN1_CONSTRUCTED | ASN1_SEQUENCE ) ) return( POLARSSL_ERR_PK_PASSWORD_MISMATCH ); decrypted = 1; } else #endif /* POLARSSL_PKCS12_C */ #if defined(POLARSSL_PKCS5_C) if( OID_CMP( OID_PKCS5_PBES2, &pbe_alg_oid ) ) { if( ( ret = pkcs5_pbes2( &pbe_params, PKCS5_DECRYPT, pwd, pwdlen, p, len, buf ) ) != 0 ) { if( ret == POLARSSL_ERR_PKCS5_PASSWORD_MISMATCH ) return( POLARSSL_ERR_PK_PASSWORD_MISMATCH ); return( ret ); } decrypted = 1; } else #endif /* POLARSSL_PKCS5_C */ { ((void) pwd); } if( decrypted == 0 ) return( POLARSSL_ERR_PK_FEATURE_UNAVAILABLE ); return( pk_parse_key_pkcs8_unencrypted_der( pk, buf, len ) ); }
int pkcs5_pbes2( asn1_buf *pbe_params, int mode, const unsigned char *pwd, size_t pwdlen, const unsigned char *data, size_t datalen, unsigned char *output ) { int ret, iterations = 0, keylen = 0; unsigned char *p, *end, *end2; asn1_buf kdf_alg_oid, enc_scheme_oid, salt; md_type_t md_type = POLARSSL_MD_SHA1; unsigned char key[32], iv[32]; size_t len = 0, olen = 0; const md_info_t *md_info; const cipher_info_t *cipher_info; md_context_t md_ctx; cipher_context_t cipher_ctx; p = pbe_params->p; end = p + pbe_params->len; /* * PBES2-params ::= SEQUENCE { * keyDerivationFunc AlgorithmIdentifier {{PBES2-KDFs}}, * encryptionScheme AlgorithmIdentifier {{PBES2-Encs}} * } */ if( ( ret = asn1_get_tag( &p, end, &len, ASN1_CONSTRUCTED | ASN1_SEQUENCE ) ) != 0 ) { return( POLARSSL_ERR_PKCS5_INVALID_FORMAT + ret ); } if( ( ret = asn1_get_tag( &p, end, &len, ASN1_CONSTRUCTED | ASN1_SEQUENCE ) ) != 0 ) { return( POLARSSL_ERR_PKCS5_INVALID_FORMAT + ret ); } end2 = p + len; if( ( ret = asn1_get_tag( &p, end2, &kdf_alg_oid.len, ASN1_OID ) ) != 0 ) return( POLARSSL_ERR_PKCS5_INVALID_FORMAT + ret ); kdf_alg_oid.p = p; p += kdf_alg_oid.len; // Only PBKDF2 supported at the moment // if( !OID_CMP( OID_PKCS5_PBKDF2, &kdf_alg_oid ) ) return( POLARSSL_ERR_PKCS5_FEATURE_UNAVAILABLE ); if( ( ret = pkcs5_parse_pbkdf2_params( &p, end2, &salt, &iterations, &keylen, &md_type ) ) != 0 ) { return( ret ); } md_info = md_info_from_type( md_type ); if( md_info == NULL ) return( POLARSSL_ERR_PKCS5_FEATURE_UNAVAILABLE ); if( ( ret = asn1_get_tag( &p, end, &len, ASN1_CONSTRUCTED | ASN1_SEQUENCE ) ) != 0 ) { return( POLARSSL_ERR_PKCS5_INVALID_FORMAT + ret ); } end2 = p + len; if( ( ret = asn1_get_tag( &p, end2, &enc_scheme_oid.len, ASN1_OID ) ) != 0 ) return( POLARSSL_ERR_PKCS5_INVALID_FORMAT + ret ); enc_scheme_oid.p = p; p += enc_scheme_oid.len; #if defined(POLARSSL_DES_C) // Only DES-CBC and DES-EDE3-CBC supported at the moment // if( OID_CMP( OID_DES_EDE3_CBC, &enc_scheme_oid ) ) { cipher_info = cipher_info_from_type( POLARSSL_CIPHER_DES_EDE3_CBC ); } else if( OID_CMP( OID_DES_CBC, &enc_scheme_oid ) ) { cipher_info = cipher_info_from_type( POLARSSL_CIPHER_DES_CBC ); } else #endif /* POLARSSL_DES_C */ return( POLARSSL_ERR_PKCS5_FEATURE_UNAVAILABLE ); if( cipher_info == NULL ) return( POLARSSL_ERR_PKCS5_FEATURE_UNAVAILABLE ); keylen = cipher_info->key_length / 8; if( ( ret = asn1_get_tag( &p, end2, &len, ASN1_OCTET_STRING ) ) != 0 ) return( POLARSSL_ERR_PKCS5_INVALID_FORMAT + ret ); if( len != cipher_info->iv_size ) return( POLARSSL_ERR_PKCS5_INVALID_FORMAT ); memcpy( iv, p, len ); if( ( ret = md_init_ctx( &md_ctx, md_info ) ) != 0 ) return( ret ); if( ( ret = cipher_init_ctx( &cipher_ctx, cipher_info ) ) != 0 ) return( ret ); if ( ( ret = pkcs5_pbkdf2_hmac( &md_ctx, pwd, pwdlen, salt.p, salt.len, iterations, keylen, key ) ) != 0 ) { return( ret ); } if( ( ret = cipher_setkey( &cipher_ctx, key, keylen, mode ) ) != 0 ) return( ret ); if( ( ret = cipher_reset( &cipher_ctx, iv ) ) != 0 ) return( ret ); if( ( ret = cipher_update( &cipher_ctx, data, datalen, output, &olen ) ) != 0 ) { return( ret ); } if( ( ret = cipher_finish( &cipher_ctx, output + olen, &olen ) ) != 0 ) return( POLARSSL_ERR_PKCS5_PASSWORD_MISMATCH ); return( 0 ); }
static int pkcs5_parse_pbkdf2_params( unsigned char **p, const unsigned char *end, asn1_buf *salt, int *iterations, int *keylen, md_type_t *md_type ) { int ret; size_t len = 0; asn1_buf prf_alg_oid; /* * PBKDF2-params ::= SEQUENCE { * salt OCTET STRING, * iterationCount INTEGER, * keyLength INTEGER OPTIONAL * prf AlgorithmIdentifier DEFAULT algid-hmacWithSHA1 * } * */ if( ( ret = asn1_get_tag( p, end, &len, ASN1_CONSTRUCTED | ASN1_SEQUENCE ) ) != 0 ) { return( POLARSSL_ERR_PKCS5_INVALID_FORMAT + ret ); } end = *p + len; if( ( ret = asn1_get_tag( p, end, &salt->len, ASN1_OCTET_STRING ) ) != 0 ) return( POLARSSL_ERR_PKCS5_INVALID_FORMAT + ret ); salt->p = *p; *p += salt->len; if( ( ret = asn1_get_int( p, end, iterations ) ) != 0 ) return( POLARSSL_ERR_PKCS5_INVALID_FORMAT + ret ); if( *p == end ) return( 0 ); if( ( ret = asn1_get_int( p, end, keylen ) ) != 0 ) { if( ret != POLARSSL_ERR_ASN1_UNEXPECTED_TAG ) return( POLARSSL_ERR_PKCS5_INVALID_FORMAT + ret ); } if( *p == end ) return( 0 ); if( ( ret = asn1_get_tag( p, end, &prf_alg_oid.len, ASN1_OID ) ) != 0 ) return( POLARSSL_ERR_PKCS5_INVALID_FORMAT + ret ); if( !OID_CMP( OID_HMAC_SHA1, &prf_alg_oid ) ) return( POLARSSL_ERR_PKCS5_FEATURE_UNAVAILABLE ); *md_type = POLARSSL_MD_SHA1; if( *p != end ) return( POLARSSL_ERR_PKCS5_INVALID_FORMAT + POLARSSL_ERR_ASN1_LENGTH_MISMATCH ); return( 0 ); }
/* * Verify the certificate validity */ int x509_crt_verify( x509_crt *crt, x509_crt *trust_ca, x509_crl *ca_crl, const char *cn, int *flags, int (*f_vrfy)(void *, x509_crt *, int, int *), void *p_vrfy ) { size_t cn_len; int ret; int pathlen = 0; x509_crt *parent; x509_name *name; x509_sequence *cur = NULL; *flags = 0; if( cn != NULL ) { name = &crt->subject; cn_len = strlen( cn ); if( crt->ext_types & EXT_SUBJECT_ALT_NAME ) { cur = &crt->subject_alt_names; while( cur != NULL ) { if( cur->buf.len == cn_len && x509_name_cmp( cn, cur->buf.p, cn_len ) == 0 ) break; if( cur->buf.len > 2 && memcmp( cur->buf.p, "*.", 2 ) == 0 && x509_wildcard_verify( cn, &cur->buf ) ) break; cur = cur->next; } if( cur == NULL ) *flags |= BADCERT_CN_MISMATCH; } else { while( name != NULL ) { if( OID_CMP( OID_AT_CN, &name->oid ) ) { if( name->val.len == cn_len && x509_name_cmp( name->val.p, cn, cn_len ) == 0 ) break; if( name->val.len > 2 && memcmp( name->val.p, "*.", 2 ) == 0 && x509_wildcard_verify( cn, &name->val ) ) break; } name = name->next; } if( name == NULL ) *flags |= BADCERT_CN_MISMATCH; } } /* * Iterate upwards in the given cert chain, to find our crt parent. * Ignore any upper cert with CA != TRUE. */ parent = crt->next; while( parent != NULL && parent->version != 0 ) { if( parent->ca_istrue == 0 || crt->issuer_raw.len != parent->subject_raw.len || memcmp( crt->issuer_raw.p, parent->subject_raw.p, crt->issuer_raw.len ) != 0 ) { parent = parent->next; continue; } break; } if( parent != NULL ) { /* * Part of the chain */ ret = x509_crt_verify_child( crt, parent, trust_ca, ca_crl, pathlen, flags, f_vrfy, p_vrfy ); if( ret != 0 ) return( ret ); } else { ret = x509_crt_verify_top( crt, trust_ca, ca_crl, pathlen, flags, f_vrfy, p_vrfy ); if( ret != 0 ) return( ret ); } if( *flags != 0 ) return( POLARSSL_ERR_X509_CERT_VERIFY_FAILED ); return( 0 ); }