diff options
author | Nikos Mavrogiannopoulos <nmav@gnutls.org> | 2003-03-23 12:16:54 +0000 |
---|---|---|
committer | Nikos Mavrogiannopoulos <nmav@gnutls.org> | 2003-03-23 12:16:54 +0000 |
commit | 1eff1dd92bb79997fb81a8dc53da7c73c4308e98 (patch) | |
tree | 3b708d93687bf7b9c694c2970df25e348c624883 | |
parent | 50e430c625cd065dbc488ccd698fb8d7c9ac7bc4 (diff) | |
download | gnutls-1eff1dd92bb79997fb81a8dc53da7c73c4308e98.tar.gz |
* Added support for encoding and decoding PKCS #8 2.0 encrypted
RSA private keys.
-rw-r--r-- | NEWS | 3 | ||||
-rw-r--r-- | includes/gnutls/x509.h | 3 | ||||
-rw-r--r-- | lib/Makefile.am | 3 | ||||
-rw-r--r-- | lib/gnutls_cipher_int.c | 7 | ||||
-rw-r--r-- | lib/gnutls_cipher_int.h | 3 | ||||
-rw-r--r-- | lib/gnutls_constate.c | 16 | ||||
-rw-r--r-- | lib/gnutls_errors.c | 2 | ||||
-rw-r--r-- | lib/x509/privkey_pkcs8.c | 620 | ||||
-rw-r--r-- | lib/x509/x509.c | 4 | ||||
-rw-r--r-- | lib/x509/x509.h | 2 |
10 files changed, 629 insertions, 34 deletions
@@ -15,7 +15,8 @@ Version 0.9.3 - Added the new functions: gnutls_certificate_set_x509_key() gnutls_certificate_set_x509_trust(), gnutls_certificate_set_x509_crl(), gnutls_x509_crt_export(), gnutls_x509_crl_export(). - +- Added support for encoding and decoding PKCS #8 2.0 encrypted + RSA private keys. Version 0.9.2 (15/03/2003) - Some corrections in the memory mapping code (file is unmapped after diff --git a/includes/gnutls/x509.h b/includes/gnutls/x509.h index e45ecd3797..e79f8aba0a 100644 --- a/includes/gnutls/x509.h +++ b/includes/gnutls/x509.h @@ -209,6 +209,9 @@ int gnutls_x509_privkey_generate( gnutls_x509_privkey key, gnutls_pk_algorithm a int gnutls_x509_privkey_export( gnutls_x509_privkey key, gnutls_x509_crt_fmt format, unsigned char* output_data, int* output_data_size); +int gnutls_x509_privkey_export_pkcs8( gnutls_x509_privkey key, + gnutls_x509_crt_fmt format, char* password, unsigned int flags, + unsigned char* output_data, int* output_data_size); int gnutls_x509_privkey_export_rsa_raw(gnutls_x509_privkey key, gnutls_datum * m, gnutls_datum *e, gnutls_datum *d, gnutls_datum *p, gnutls_datum* q, diff --git a/lib/Makefile.am b/lib/Makefile.am index 5dc76ce949..f28b5d7a0e 100644 --- a/lib/Makefile.am +++ b/lib/Makefile.am @@ -49,7 +49,8 @@ libgnutls_la_SOURCES = $(COBJECTS) libgnutls_la_LIBADD = $(MINITASN1_OBJECTS) x509/dn.lo x509/crl.lo x509/common.lo \ x509/x509.lo x509/extensions.lo x509/compat.lo x509/verify.lo \ - x509/mpi.lo x509/privkey.lo x509/pkcs7.lo + x509/mpi.lo x509/privkey.lo x509/pkcs7.lo x509/crq.lo x509/xml.lo x509/sign.lo \ + x509/pkcs5.lo x509/privkey_pkcs8.lo libgnutls_la_LDFLAGS = $(LIBASN1_LINK) $(LIBGCRYPT_LIBS) \ -version-info $(LT_CURRENT):$(LT_REVISION):$(LT_AGE) #-export-symbols gnutls.sym diff --git a/lib/gnutls_cipher_int.c b/lib/gnutls_cipher_int.c index 7ca96386a2..2f7badadd3 100644 --- a/lib/gnutls_cipher_int.c +++ b/lib/gnutls_cipher_int.c @@ -24,7 +24,8 @@ #include <gnutls_cipher_int.h> #include <gnutls_datum.h> -GNUTLS_CIPHER_HANDLE _gnutls_cipher_init( gnutls_cipher_algorithm cipher, gnutls_datum key, gnutls_datum iv) +GNUTLS_CIPHER_HANDLE _gnutls_cipher_init( gnutls_cipher_algorithm cipher, + const gnutls_datum *key, const gnutls_datum *iv) { GNUTLS_CIPHER_HANDLE ret; @@ -52,8 +53,8 @@ GNUTLS_CIPHER_HANDLE ret; ret = GNUTLS_CIPHER_FAILED; } if (ret!=GNUTLS_CIPHER_FAILED) { - gcry_cipher_setkey(ret, key.data, key.size); - if (iv.data!=NULL && iv.size>0) gcry_cipher_setiv(ret, iv.data, iv.size); + gcry_cipher_setkey(ret, key->data, key->size); + if (iv->data!=NULL && iv->size>0) gcry_cipher_setiv(ret, iv->data, iv->size); } return ret; diff --git a/lib/gnutls_cipher_int.h b/lib/gnutls_cipher_int.h index 0f2e55439b..5a049597f4 100644 --- a/lib/gnutls_cipher_int.h +++ b/lib/gnutls_cipher_int.h @@ -24,7 +24,8 @@ #define GNUTLS_CIPHER_HANDLE GCRY_CIPHER_HD #define GNUTLS_CIPHER_FAILED NULL -GNUTLS_CIPHER_HANDLE _gnutls_cipher_init( gnutls_cipher_algorithm cipher, gnutls_datum key, gnutls_datum iv); +GNUTLS_CIPHER_HANDLE _gnutls_cipher_init( gnutls_cipher_algorithm cipher, + const gnutls_datum *key, const gnutls_datum *iv); int _gnutls_cipher_encrypt(GNUTLS_CIPHER_HANDLE handle, void* text, int textlen); int _gnutls_cipher_decrypt(GNUTLS_CIPHER_HANDLE handle, void* ciphertext, int ciphertextlen); void _gnutls_cipher_deinit(GNUTLS_CIPHER_HANDLE handle); diff --git a/lib/gnutls_constate.c b/lib/gnutls_constate.c index feffe96b6b..01fe09899a 100644 --- a/lib/gnutls_constate.c +++ b/lib/gnutls_constate.c @@ -541,9 +541,9 @@ int _gnutls_read_connection_state_init(gnutls_session session) session->connection_state.read_cipher_state = _gnutls_cipher_init(session->security_parameters. read_bulk_cipher_algorithm, - session->cipher_specs. + &session->cipher_specs. client_write_key, - session->cipher_specs. + &session->cipher_specs. client_write_IV); if (session->connection_state.read_cipher_state == GNUTLS_CIPHER_FAILED @@ -575,9 +575,9 @@ int _gnutls_read_connection_state_init(gnutls_session session) session->connection_state.read_cipher_state = _gnutls_cipher_init(session->security_parameters. read_bulk_cipher_algorithm, - session->cipher_specs. + &session->cipher_specs. server_write_key, - session->cipher_specs. + &session->cipher_specs. server_write_IV); if (session->connection_state.read_cipher_state == @@ -724,9 +724,9 @@ int _gnutls_write_connection_state_init(gnutls_session session) session->connection_state.write_cipher_state = _gnutls_cipher_init(session->security_parameters. write_bulk_cipher_algorithm, - session->cipher_specs. + &session->cipher_specs. server_write_key, - session->cipher_specs. + &session->cipher_specs. server_write_IV); if (session->connection_state.write_cipher_state == @@ -761,9 +761,9 @@ int _gnutls_write_connection_state_init(gnutls_session session) session->connection_state.write_cipher_state = _gnutls_cipher_init(session->security_parameters. write_bulk_cipher_algorithm, - session->cipher_specs. + &session->cipher_specs. client_write_key, - session->cipher_specs. + &session->cipher_specs. client_write_IV); if (session->connection_state.write_cipher_state == diff --git a/lib/gnutls_errors.c b/lib/gnutls_errors.c index 7f775e5758..a52c2de627 100644 --- a/lib/gnutls_errors.c +++ b/lib/gnutls_errors.c @@ -240,6 +240,8 @@ int _gnutls_asn2err( int asn_err) { return GNUTLS_E_ASN1_SYNTAX_ERROR; case ASN1_MEM_ERROR: return GNUTLS_E_SHORT_MEMORY_BUFFER; + case ASN1_MEM_ALLOC_ERROR: + return GNUTLS_E_MEMORY_ERROR; case ASN1_DER_OVERFLOW: return GNUTLS_E_ASN1_DER_OVERFLOW; default: diff --git a/lib/x509/privkey_pkcs8.c b/lib/x509/privkey_pkcs8.c index c0613cbd3a..453c305f1e 100644 --- a/lib/x509/privkey_pkcs8.c +++ b/lib/x509/privkey_pkcs8.c @@ -34,6 +34,15 @@ #include <extensions.h> #include <mpi.h> #include <gnutls_algorithms.h> +#include <gnutls_random.h> +#include <gnutls_num.h> + +#define PBES2_OID "1.2.840.113549.1.5.13" +#define PBKDF2_OID "1.2.840.113549.1.5.12" +#define DES_EDE3_CBC_OID "1.2.840.113549.3.7" + +/* oid_pbeWithSHAAnd3_KeyTripleDES_CBC */ +#define PBE_3DES_SHA1_OID "1.2.840.113549.1.12.1.3" struct pbkdf2_params { opaque salt[32]; @@ -47,6 +56,8 @@ struct pbe_enc_params { int iv_size; }; +static int generate_key( const char* password, unsigned int flags, struct pbkdf2_params* kdf_params, + struct pbe_enc_params* enc_params, gnutls_datum * key); static int read_pbkdf2_params( ASN1_TYPE pbes2_asn, const gnutls_datum* der, struct pbkdf2_params* params); static int read_pbe_enc_params( ASN1_TYPE pbes2_asn, const gnutls_datum* der, @@ -55,13 +66,227 @@ static int decrypt_data( ASN1_TYPE pkcs8_asn, char* password, const struct pbkdf2_params* kdf_params, const struct pbe_enc_params *enc_params, gnutls_datum* decrypted_data); static ASN1_TYPE decode_private_key_info( const gnutls_datum* der, gnutls_x509_privkey pkey); +static int write_pbe2_params( ASN1_TYPE pkcs8_asn, const struct pbkdf2_params* kdf_params, + const struct pbe_enc_params* enc_params); +static int _der_encode_and_copy( ASN1_TYPE src, const char* src_name, + ASN1_TYPE dest, const char* dest_name); +static int encrypt_data( const gnutls_datum* plain, + const struct pbe_enc_params *enc_params, + gnutls_datum* key, gnutls_datum* encrypted); #define PEM_PKCS8 "ENCRYPTED PRIVATE KEY" + +/* + * Encodes a PKCS #1 private key to a PKCS #8 private key + * info. The output will be allocated and stored into der. + */ +static int encode_to_private_key_info( gnutls_x509_privkey pkey, gnutls_datum* der) +{ + int result, size; + opaque *data = NULL; + ASN1_TYPE pkcs8_asn = ASN1_TYPE_EMPTY; + opaque null = 0; + + if (pkey->pk_algorithm != GNUTLS_PK_RSA) { + gnutls_assert(); + return GNUTLS_E_UNIMPLEMENTED_FEATURE; + } + + if ((result = + asn1_create_element(_gnutls_get_pkix(), + "PKIX1.PrivateKeyInfo", &pkcs8_asn + )) != ASN1_SUCCESS) { + gnutls_assert(); + result = _gnutls_asn2err(result); + goto error; + } + + /* Write the version. + */ + result = asn1_write_value( pkcs8_asn, "version", &null, 1); + if (result != ASN1_SUCCESS) { + gnutls_assert(); + result = _gnutls_asn2err(result); + goto error; + } + + /* write the privateKeyAlgorithm + * fields. (OID+NULL data) + */ + result = asn1_write_value( pkcs8_asn, "privateKeyAlgorithm.algorithm", PKIX1_RSA_OID, 1); + if (result != ASN1_SUCCESS) { + gnutls_assert(); + result = _gnutls_asn2err(result); + goto error; + } + + result = asn1_write_value( pkcs8_asn, "privateKeyAlgorithm.parameters", NULL, 0); + if (result != ASN1_SUCCESS) { + gnutls_assert(); + result = _gnutls_asn2err(result); + goto error; + } + + /* Write the raw private key + */ + result = gnutls_x509_privkey_export( pkey, GNUTLS_X509_FMT_DER, NULL, &size); + if (result != GNUTLS_E_SHORT_MEMORY_BUFFER) { + gnutls_assert(); + goto error; + } + + data = gnutls_alloca( size); + if (data == NULL) { + gnutls_assert(); + result = GNUTLS_E_MEMORY_ERROR; + goto error; + } + + + result = gnutls_x509_privkey_export( pkey, GNUTLS_X509_FMT_DER, data, &size); + if (result < 0) { + gnutls_assert(); + goto error; + } + + result = asn1_write_value( pkcs8_asn, "privateKey", data, size); + + gnutls_afree( data); + data = NULL; + + if (result != ASN1_SUCCESS) { + gnutls_assert(); + result = _gnutls_asn2err(result); + goto error; + } + + /* Append an empty Attributes field. + */ + result = asn1_write_value( pkcs8_asn, "attributes", NULL, 0); + if (result != ASN1_SUCCESS) { + gnutls_assert(); + result = _gnutls_asn2err(result); + goto error; + } + + /* DER Encode the generated private key info. + */ + size = 0; + result = asn1_der_coding( pkcs8_asn, "", NULL, &size, NULL); + if (result != ASN1_MEM_ERROR) { + gnutls_assert(); + result = _gnutls_asn2err(result); + goto error; + } + + /* allocate data for the der + */ + der->size = size; + der->data = gnutls_malloc( size); + if (der->data == NULL) { + gnutls_assert(); + return GNUTLS_E_MEMORY_ERROR; + } + + result = asn1_der_coding( pkcs8_asn, "", der->data, &size, NULL); + if (result != ASN1_SUCCESS) { + gnutls_assert(); + result = _gnutls_asn2err(result); + goto error; + } + + asn1_delete_structure( &pkcs8_asn); + + return 0; + + error: + asn1_delete_structure( &pkcs8_asn); + if (data != NULL) { gnutls_afree(data); } + return result; + +} + +/* Converts a PKCS #8 private key info to + * a PKCS #8 EncryptedPrivateKeyInfo. + */ +static ASN1_TYPE encode_to_pkcs8_key( gnutls_x509_privkey pkey, + const gnutls_datum *raw_key, char* password, unsigned int flags) +{ + int result; + gnutls_datum key = {NULL, 0}; + gnutls_datum tmp = {NULL, 0}; + ASN1_TYPE pkcs8_asn = ASN1_TYPE_EMPTY; + struct pbkdf2_params kdf_params; + struct pbe_enc_params enc_params; + + + if ((result = + asn1_create_element(_gnutls_get_pkix(), + "PKIX1.EncryptedPrivateKeyInfo", &pkcs8_asn + )) != ASN1_SUCCESS) { + gnutls_assert(); + goto error; + } + + /* Write the encryption schema OID + */ + result = asn1_write_value( pkcs8_asn, "encryptionAlgorithm.algorithm", PBES2_OID, 1); + if (result != ASN1_SUCCESS) { + gnutls_assert(); + goto error; + } + + /* Generate a symmetric key. + */ + result = generate_key( password, flags, &kdf_params, &enc_params, &key); + if (result < 0) { + gnutls_assert(); + goto error; + } + + result = write_pbe2_params( pkcs8_asn, &kdf_params, &enc_params); + if (result < 0) { + gnutls_assert(); + goto error; + } + + /* Parameters have been decoded. Now + * decrypt the EncryptedData. + */ + result = encrypt_data( raw_key, &enc_params, &key, &tmp); + if (result < 0) { + gnutls_assert(); + goto error; + } + + /* write the encrypted data. + */ + result = asn1_write_value( pkcs8_asn, "encryptedData", tmp.data, tmp.size); + if (result != ASN1_SUCCESS) { + gnutls_assert(); + goto error; + } + + _gnutls_free_datum( &tmp); + _gnutls_free_datum( &key); + + return pkcs8_asn; + + error: + _gnutls_free_datum( &key); + _gnutls_free_datum( &tmp); + asn1_delete_structure(&pkcs8_asn); + return NULL; +} + + /** * gnutls_x509_privkey_export_pkcs8 - This function will export the private key to PKCS8 format * @key: Holds the key * @format: the format of output params. One of PEM or DER. + * @password: the password that will be used to encrypt the key + * @flags: reserved for future use * @output_data: will contain a private key PEM or DER encoded * @output_data_size: holds the size of output_data (and will be replaced by the actual size of parameters) * @@ -77,24 +302,43 @@ static ASN1_TYPE decode_private_key_info( const gnutls_datum* der, gnutls_x509_p * 0 on success. * **/ -int gnutls_x509_privkey_export( gnutls_x509_privkey key, - gnutls_x509_crt_fmt format, unsigned char* output_data, int* output_data_size) +int gnutls_x509_privkey_export_pkcs8( gnutls_x509_privkey key, + gnutls_x509_crt_fmt format, char* password, unsigned int flags, + unsigned char* output_data, int* output_data_size) { -// NOT YET READY - return _gnutls_x509_export_int( key->key, format, PEM_PKCS8, *output_data_size, +ASN1_TYPE pkcs8_asn; +int ret; +gnutls_datum tmp; + + /* Get the private key info + */ + ret = encode_to_private_key_info( key, &tmp); + if ( ret < 0) { + gnutls_assert(); + return ret; + } + + + pkcs8_asn = encode_to_pkcs8_key( key, &tmp, password, flags); + _gnutls_free_datum( &tmp); + + if (pkcs8_asn == NULL) { + gnutls_assert(); + return GNUTLS_E_ASN1_GENERIC_ERROR; + } + + ret = _gnutls_x509_export_int( pkcs8_asn, format, PEM_PKCS8, *output_data_size, output_data, output_data_size); + + asn1_delete_structure( &pkcs8_asn); + return ret; } -#define PBES2_OID "1.2.840.113549.1.5.13" -#define PBKDF2_OID "1.2.840.113549.1.5.12" -#define DES_EDE3_CBC_OID "1.2.840.113549.3.7" -/* oid_pbeWithSHAAnd3_KeyTripleDES_CBC */ -#define PBE_3DES_SHA1_OID "1.2.840.113549.1.12.1.3" - -/* Converts a PKCS#8 key to +/* Converts a PKCS #8 key to * an internal structure (gnutls_private_key) + * (normally a PKCS #1 encoded RSA key) */ static ASN1_TYPE decode_pkcs8_key( const gnutls_datum *raw_key, char* password, gnutls_x509_privkey pkey) @@ -295,12 +539,13 @@ static ASN1_TYPE decode_private_key_info( const gnutls_datum* der, gnutls_x509_p } + /** * gnutls_x509_privkey_import_pkcs8 - This function will import a DER or PEM PKCS8 encoded key * @key: The structure to store the parsed key * @data: The DER or PEM encoded certificate. * @format: One of DER or PEM - * @pass: the password to decode + * @password: the password to decrypt the key * * This function will convert the given DER or PEM encoded PKCS8 2.0 encrypted key * to the native gnutls_x509_privkey format. The output will be stored in 'key'. @@ -311,7 +556,7 @@ static ASN1_TYPE decode_private_key_info( const gnutls_datum* der, gnutls_x509_p * **/ int gnutls_x509_privkey_import_pkcs8(gnutls_x509_privkey key, const gnutls_datum * data, - gnutls_x509_crt_fmt format, char * pass) + gnutls_x509_crt_fmt format, char * password) { int result = 0, need_free = 0; gnutls_datum _data = { data->data, data->size }; @@ -340,7 +585,7 @@ int gnutls_x509_privkey_import_pkcs8(gnutls_x509_privkey key, const gnutls_datum } - key->key = decode_pkcs8_key( &_data, pass, key); + key->key = decode_pkcs8_key( &_data, password, key); if (key->key == NULL) { gnutls_assert(); result = GNUTLS_E_ASN1_DER_ERROR; @@ -380,6 +625,7 @@ char oid[64]; gnutls_assert(); return _gnutls_asn2err(result); } + _gnutls_hard_log( "keyDerivationFunc.algorithm: %s\n", oid); if (strcmp( oid, PBKDF2_OID) != 0) { gnutls_assert(); @@ -421,6 +667,7 @@ char oid[64]; result = _gnutls_asn2err(result); goto error; } + _gnutls_hard_log( "salt.specified.size: %d\n", params->salt_size); /* read the iteration count */ @@ -430,7 +677,7 @@ char oid[64]; gnutls_assert(); goto error; } - + _gnutls_hard_log( "iterationCount: %d\n", params->iter_count); /* read the keylength, if it is set. */ @@ -440,6 +687,7 @@ char oid[64]; if (result < 0) { params->key_size = 0; } + _gnutls_hard_log( "keyLength: %d\n", params->key_size); /* We don't read the PRF. We only use the default. */ @@ -470,6 +718,7 @@ char oid[64]; gnutls_assert(); goto error; } + _gnutls_hard_log( "encryptionScheme.algorithm: %s\n", oid); if (strcmp( oid, DES_EDE3_CBC_OID) != 0) { gnutls_assert(); @@ -502,7 +751,7 @@ char oid[64]; goto error; } - /* read the salt */ + /* read the IV */ params->iv_size = sizeof(params->iv); result = asn1_read_value( pbe_asn, "", params->iv, ¶ms->iv_size); if (result != ASN1_SUCCESS) { @@ -510,6 +759,7 @@ char oid[64]; result = _gnutls_asn2err(result); goto error; } + _gnutls_hard_log( "IV.size: %d\n", params->iv_size); return 0; @@ -525,7 +775,7 @@ static int decrypt_data( ASN1_TYPE pkcs8_asn, char* password, { int result; int data_size; -opaque* data, *key; +opaque* data=NULL, *key = NULL; gnutls_datum dkey, div; GNUTLS_CIPHER_HANDLE ch = NULL; int key_size; @@ -580,9 +830,10 @@ int key_size; div.data = (opaque*) enc_params->iv; div.size = enc_params->iv_size; - ch = _gnutls_cipher_init( GNUTLS_CIPHER_3DES_CBC, dkey, div); + ch = _gnutls_cipher_init( GNUTLS_CIPHER_3DES_CBC, &dkey, &div); gnutls_afree( key); + key = NULL; if (ch == NULL) { gnutls_assert(); @@ -605,7 +856,340 @@ int key_size; error: gnutls_free(data); + gnutls_afree(key); + if (ch!=NULL) + _gnutls_cipher_deinit( ch); + return result; +} + + + +/* DER Encodes the src ASN1_TYPE and stores it to + * dest in dest_name. Usefull to encode something and store it + * as OCTET. + */ +static int _der_encode_and_copy( ASN1_TYPE src, const char* src_name, + ASN1_TYPE dest, const char* dest_name) +{ +int size, result; +opaque *data = NULL; + + size = 0; + result = asn1_der_coding( src, src_name, NULL, &size, NULL); + if (result != ASN1_MEM_ERROR) { + gnutls_assert(); + return _gnutls_asn2err(result); + } + + /* allocate data for the der + */ + data = gnutls_alloca( size); + if (data == NULL) { + gnutls_assert(); + return GNUTLS_E_MEMORY_ERROR; + } + + result = asn1_der_coding( src, src_name, data, &size, NULL); + if (result != ASN1_SUCCESS) { + gnutls_assert(); + gnutls_afree(data); + return _gnutls_asn2err(result); + } + + /* Write the key derivation algorithm + */ + result = asn1_write_value( dest, dest_name, data, size); + if (result != ASN1_SUCCESS) { + gnutls_assert(); + gnutls_afree(data); + return _gnutls_asn2err(result); + } + + return 0; +} + + +/* Writes the PBKDF2 parameters. + */ +static int write_pbkdf2_params( ASN1_TYPE pbes2_asn, const struct pbkdf2_params *kdf_params) +{ +int result; +ASN1_TYPE pbkdf2_asn = ASN1_TYPE_EMPTY; +char tmp[64]; + + /* Write the key derivation algorithm + */ + result = asn1_write_value( pbes2_asn, "keyDerivationFunc.algorithm", PBKDF2_OID, 1); + if (result != ASN1_SUCCESS) { + gnutls_assert(); + return _gnutls_asn2err(result); + } + + /* Now write the key derivation and the encryption + * functions. + */ + if ((result = + asn1_create_element(_gnutls_get_pkix(), + "PKIX1.pkcs-5-PBKDF2-params", &pbkdf2_asn + )) != ASN1_SUCCESS) { + gnutls_assert(); + return _gnutls_asn2err(result); + } + + result = asn1_write_value( pbkdf2_asn, "salt", "specified", 1); + if (result != ASN1_SUCCESS) { + gnutls_assert(); + result = _gnutls_asn2err(result); + goto error; + } + + /* write the salt + */ + result = asn1_write_value( pbkdf2_asn, "salt.specified", kdf_params->salt, kdf_params->salt_size); + if (result != ASN1_SUCCESS) { + gnutls_assert(); + result = _gnutls_asn2err(result); + goto error; + } + _gnutls_hard_log( "salt.specified.size: %d\n", kdf_params->salt_size); + + /* write the iteration count + */ + _gnutls_write_uint32( kdf_params->iter_count, tmp); + + result = asn1_write_value( pbkdf2_asn, "iterationCount", tmp, 4); + if (result != ASN1_SUCCESS) { + gnutls_assert(); + result = _gnutls_asn2err(result); + goto error; + } + _gnutls_hard_log( "iterationCount: %d\n", kdf_params->iter_count); + + /* write the keylength, if it is set. + */ + result = asn1_write_value( pbkdf2_asn, "keyLength", NULL, 0); + if (result != ASN1_SUCCESS) { + gnutls_assert(); + result = _gnutls_asn2err(result); + goto error; + } + + /* We write an emptry prf. + */ + result = asn1_write_value( pbkdf2_asn, "prf", NULL, 0); + if (result != ASN1_SUCCESS) { + gnutls_assert(); + result = _gnutls_asn2err(result); + goto error; + } + + /* now encode them an put the DER output + * in the keyDerivationFunc.parameters + */ + result = _der_encode_and_copy( pbkdf2_asn, "", + pbes2_asn, "keyDerivationFunc.parameters"); + if (result < 0) { + gnutls_assert(); + goto error; + } + + return 0; + + error: + asn1_delete_structure( &pbkdf2_asn); + return result; + +} + +static int write_pbe_enc_params( ASN1_TYPE pbes2_asn, const struct pbe_enc_params* params) +{ +int result; +ASN1_TYPE pbe_asn = ASN1_TYPE_EMPTY; + + /* Write the encryption algorithm + */ + result = asn1_write_value( pbes2_asn, "encryptionScheme.algorithm", DES_EDE3_CBC_OID, 1); + if (result != ASN1_SUCCESS) { + gnutls_assert(); + goto error; + } + _gnutls_hard_log( "encryptionScheme.algorithm: %s\n", DES_EDE3_CBC_OID); + + /* Now check the encryption parameters. + */ + if ((result = + asn1_create_element(_gnutls_get_pkix(), + "PKIX1.pkcs-5-des-EDE3-CBC-params", &pbe_asn + )) != ASN1_SUCCESS) { + gnutls_assert(); + return _gnutls_asn2err(result); + } + + /* read the salt */ + result = asn1_write_value( pbe_asn, "", params->iv, params->iv_size); + if (result != ASN1_SUCCESS) { + gnutls_assert(); + result = _gnutls_asn2err(result); + goto error; + } + _gnutls_hard_log( "IV.size: %d\n", params->iv_size); + + /* now encode them an put the DER output + * in the encryptionScheme.parameters + */ + result = _der_encode_and_copy( pbe_asn, "", + pbes2_asn, "encryptionScheme.parameters"); + if (result < 0) { + gnutls_assert(); + goto error; + } + + return 0; + + error: + asn1_delete_structure( &pbe_asn); + return result; + +} + +/* Generates a key and also stores the key parameters. + */ +static int generate_key( const char* password, unsigned int flags, + struct pbkdf2_params* kdf_params, + struct pbe_enc_params* enc_params, gnutls_datum * key) +{ +opaque rnd[2]; +int ret; + + _gnutls_get_random( rnd, 2, GNUTLS_STRONG_RANDOM); + + /* generate salt */ + kdf_params->salt_size = GMIN( sizeof( kdf_params->salt), (uint)(10 + (rnd[1] % 10))); + _gnutls_get_random( kdf_params->salt, kdf_params->salt_size, GNUTLS_STRONG_RANDOM); + + kdf_params->iter_count = 256 + rnd[0]; + key->size = kdf_params->key_size = gnutls_cipher_get_key_size( GNUTLS_CIPHER_3DES_CBC); /* for 3 DES */ + + enc_params->iv_size = 8; /* ok for 3DES */ + _gnutls_get_random( enc_params->iv, enc_params->iv_size, GNUTLS_WEAK_RANDOM); + + key->data = gnutls_secure_malloc( key->size); + if (key->data == NULL) { + gnutls_assert(); + return GNUTLS_E_MEMORY_ERROR; + } + + /* now generate the key. + */ + ret = _gnutls_pkcs5_pbkdf2 ( PKCS5_PRF_SHA1, password, + strlen(password), kdf_params->salt, kdf_params->salt_size, + kdf_params->iter_count, kdf_params->key_size, key->data); + if (ret != PKCS5_OK) { + gnutls_assert(); + return GNUTLS_E_ENCRYPTION_FAILED; + } + + return 0; +} + + +/* Encodes the parameters to be written in the encryptionAlgorithm.parameters + * part. + */ +static int write_pbe2_params( ASN1_TYPE pkcs8_asn, const struct pbkdf2_params* kdf_params, + const struct pbe_enc_params* enc_params) +{ +int result; +ASN1_TYPE pbes2_asn = ASN1_TYPE_EMPTY; + + if ((result = + asn1_create_element(_gnutls_get_pkix(), + "PKIX1.pkcs-5-PBES2-params", &pbes2_asn + )) != ASN1_SUCCESS) { + gnutls_assert(); + return _gnutls_asn2err(result); + } + + result = write_pbkdf2_params( pbes2_asn, kdf_params); + if (result < 0) { + gnutls_assert(); + goto error; + } + + result = write_pbe_enc_params( pbes2_asn, enc_params); + if (result < 0) { + gnutls_assert(); + goto error; + } + + result = _der_encode_and_copy( pbes2_asn, "", + pkcs8_asn, "encryptionAlgorithm.parameters"); + if (result < 0) { + gnutls_assert(); + goto error; + } + + asn1_delete_structure( &pbes2_asn); + + return 0; + + error: + asn1_delete_structure( &pbes2_asn); + return result; + +} + +static int encrypt_data( const gnutls_datum* plain, + const struct pbe_enc_params *enc_params, + gnutls_datum* key, gnutls_datum* encrypted) +{ +int result; +int data_size; +opaque* data=NULL; +gnutls_datum div; +GNUTLS_CIPHER_HANDLE ch = NULL; +opaque pad; + + data = gnutls_malloc( plain->size + 8); + if (data == NULL) { + gnutls_assert(); + return GNUTLS_E_MEMORY_ERROR; + } + + memcpy( data, plain->data, plain->size); + pad = 8 - (plain->size % 8); + if ( pad == 0) pad = 8; + + memset( &data[plain->size], pad, pad); + data_size = plain->size + pad; + + div.data = (opaque*) enc_params->iv; + div.size = enc_params->iv_size; + ch = _gnutls_cipher_init( GNUTLS_CIPHER_3DES_CBC, key, &div); + + if (ch == GNUTLS_CIPHER_FAILED) { + gnutls_assert(); + result = GNUTLS_E_ENCRYPTION_FAILED; + goto error; + } + + result = _gnutls_cipher_encrypt( ch, data, data_size); + if (result < 0) { + gnutls_assert(); + goto error; + } + + encrypted->data = data; + encrypted->size = data_size; + + _gnutls_cipher_deinit( ch); + + return 0; + + error: + gnutls_free(data); if (ch!=NULL) _gnutls_cipher_deinit( ch); return result; } + diff --git a/lib/x509/x509.c b/lib/x509/x509.c index 74be296acc..0df385b2cd 100644 --- a/lib/x509/x509.c +++ b/lib/x509/x509.c @@ -1099,16 +1099,16 @@ int _gnutls_x509_export_int( ASN1_TYPE asn1_data, int tmp_buf_size, unsigned char* output_data, int* output_data_size) { int result; + if (tmp_buf_size == 0) tmp_buf_size = 16*1024; if (format == GNUTLS_X509_FMT_DER) { if (output_data == NULL) *output_data_size = 0; if ((result=asn1_der_coding( asn1_data, "", output_data, output_data_size, NULL)) != ASN1_SUCCESS) { - gnutls_assert(); - if (result == ASN1_MEM_ERROR) return GNUTLS_E_SHORT_MEMORY_BUFFER; + gnutls_assert(); return _gnutls_asn2err(result); } diff --git a/lib/x509/x509.h b/lib/x509/x509.h index b1f5d07975..ee066a0c3d 100644 --- a/lib/x509/x509.h +++ b/lib/x509/x509.h @@ -134,6 +134,8 @@ int gnutls_x509_privkey_export_rsa_raw(gnutls_x509_privkey key, gnutls_datum * m, gnutls_datum *e, gnutls_datum *d, gnutls_datum *p, gnutls_datum* q, gnutls_datum* u); +int gnutls_x509_privkey_export( gnutls_x509_privkey key, + gnutls_x509_crt_fmt format, unsigned char* output_data, int* output_data_size); int _gnutls_x509_export_int( ASN1_TYPE asn1_data, gnutls_x509_crt_fmt format, char* pem_header, |