PKCS#5 v2 PBES2 support and use in PKCS#8 encrypted certificates

The error code POLARSSL_ERR_X509_PASSWORD_MISMATCH is now properly
returned in case of an encryption failure in the padding. The
POLARSSL_ERR_X509_PASSWORD_REQUIRED error code is only returned for PEM
formatted private keys as for DER formatted ones it is impossible to
distinguish if a DER blob is PKCS#8 encrypted or not.
This commit is contained in:
Paul Bakker 2013-06-17 15:14:42 +02:00
parent 19bd297dc8
commit 1fd4321ba2
11 changed files with 380 additions and 10 deletions

View file

@ -233,6 +233,17 @@ void error_strerror( int ret, char *buf, size_t buflen )
snprintf( buf, buflen, "PKCS12 - PBE ASN.1 data not as expected" );
#endif /* POLARSSL_PKCS12_C */
#if defined(POLARSSL_PKCS5_C)
if( use_ret == -(POLARSSL_ERR_PKCS5_BAD_INPUT_DATA) )
snprintf( buf, buflen, "PKCS5 - Bad input parameters to function" );
if( use_ret == -(POLARSSL_ERR_PKCS5_INVALID_FORMAT) )
snprintf( buf, buflen, "PKCS5 - Unexpected ASN.1 data" );
if( use_ret == -(POLARSSL_ERR_PKCS5_FEATURE_UNAVAILABLE) )
snprintf( buf, buflen, "PKCS5 - Requested encryption or digest alg not available" );
if( use_ret == -(POLARSSL_ERR_PKCS5_PASSWORD_MISMATCH) )
snprintf( buf, buflen, "PKCS5 - Given private key password does not allow for correct decryption" );
#endif /* POLARSSL_PKCS5_C */
#if defined(POLARSSL_RSA_C)
if( use_ret == -(POLARSSL_ERR_RSA_BAD_INPUT_DATA) )
snprintf( buf, buflen, "RSA - Bad input parameters to function" );
@ -373,6 +384,10 @@ void error_strerror( int ret, char *buf, size_t buflen )
snprintf( buf, buflen, "X509 - Allocation of memory failed" );
if( use_ret == -(POLARSSL_ERR_X509_FILE_IO_ERROR) )
snprintf( buf, buflen, "X509 - Read/write of file failed" );
if( use_ret == -(POLARSSL_ERR_X509_PASSWORD_REQUIRED) )
snprintf( buf, buflen, "X509 - Private key password can't be empty" );
if( use_ret == -(POLARSSL_ERR_X509_PASSWORD_MISMATCH) )
snprintf( buf, buflen, "X509 - Given private key password does not allow for correct decryption" );
#endif /* POLARSSL_X509_PARSE_C */
if( strlen( buf ) == 0 )
@ -548,11 +563,6 @@ void error_strerror( int ret, char *buf, size_t buflen )
snprintf( buf, buflen, "PBKDF2 - Bad input parameters to function" );
#endif /* POLARSSL_PBKDF2_C */
#if defined(POLARSSL_PKCS5_C)
if( use_ret == -(POLARSSL_ERR_PKCS5_BAD_INPUT_DATA) )
snprintf( buf, buflen, "PKCS5 - Bad input parameters to function" );
#endif /* POLARSSL_PKCS5_C */
#if defined(POLARSSL_SHA1_C)
if( use_ret == -(POLARSSL_ERR_SHA1_FILE_IO_ERROR) )
snprintf( buf, buflen, "SHA1 - Read/write error in file" );

View file

@ -38,6 +38,207 @@
#if defined(POLARSSL_PKCS5_C)
#include "polarssl/pkcs5.h"
#include "polarssl/asn1.h"
#include "polarssl/cipher.h"
#define OID_CMP(oid_str, oid_buf) \
( ( OID_SIZE(oid_str) == (oid_buf)->len ) && \
memcmp( (oid_str), (oid_buf)->p, (oid_buf)->len) == 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 );
}
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 );
}
int pkcs5_pbkdf2_hmac( md_context_t *ctx, const unsigned char *password,
size_t plen, const unsigned char *salt, size_t slen,

View file

@ -62,6 +62,9 @@
#endif
#include "polarssl/dhm.h"
#include "polarssl/pkcs12.h"
#if defined(POLARSSL_PKCS5_C)
#include "polarssl/pkcs5.h"
#endif
#include <string.h>
#include <stdlib.h>
@ -2219,6 +2222,9 @@ static int x509parse_key_pkcs8_encrypted_der(
p = (unsigned char *) key;
end = p + keylen;
if( pwdlen == 0 )
return( POLARSSL_ERR_X509_PASSWORD_REQUIRED );
/*
* This function parses the EncryptedPrivatKeyInfo object (PKCS#8)
*
@ -2302,6 +2308,19 @@ static int x509parse_key_pkcs8_encrypted_der(
return( ret );
}
}
#if defined(POLARSSL_PKCS5_C)
else 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_X509_PASSWORD_MISMATCH );
return( ret );
}
}
#endif /* POLARSSL_PKCS5_C */
else
return( POLARSSL_ERR_X509_FEATURE_UNAVAILABLE );
@ -2401,14 +2420,22 @@ int x509parse_key( rsa_context *rsa, const unsigned char *key, size_t keylen,
}
rsa_free( rsa );
if( ret == POLARSSL_ERR_X509_PASSWORD_MISMATCH )
{
return( ret );
}
if( ( ret = x509parse_key_pkcs8_unencrypted_der( rsa, key, keylen ) ) == 0 )
return( 0 );
rsa_free( rsa );
if( ( ret = x509parse_key_pkcs1_der( rsa, key, keylen ) ) == 0 )
return( 0 );
rsa_free( rsa );
return( POLARSSL_ERR_X509_KEY_INVALID_FORMAT );
}