]> git.ipfire.org Git - thirdparty/gnutls.git/commitdiff
* Added support for encoding and decoding PKCS #8 2.0 encrypted
authorNikos Mavrogiannopoulos <nmav@gnutls.org>
Sun, 23 Mar 2003 12:16:54 +0000 (12:16 +0000)
committerNikos Mavrogiannopoulos <nmav@gnutls.org>
Sun, 23 Mar 2003 12:16:54 +0000 (12:16 +0000)
  RSA private keys.

NEWS
includes/gnutls/x509.h
lib/Makefile.am
lib/gnutls_cipher_int.c
lib/gnutls_cipher_int.h
lib/gnutls_constate.c
lib/gnutls_errors.c
lib/x509/privkey_pkcs8.c
lib/x509/x509.c
lib/x509/x509.h

diff --git a/NEWS b/NEWS
index 572fc175ede259446d399872fdbada872a6953ad..260472b9736a647c0e8401878295f3490ffb56ab 100644 (file)
--- a/NEWS
+++ b/NEWS
@@ -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 
index e45ecd37977f2ff94d0b85d7f36170a5777a2063..e79f8aba0af277df5db032fcf568b6878310caa9 100644 (file)
@@ -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, 
index 5dc76ce9491cdb7912067c611947ebbb2bdaf280..f28b5d7a0ecf07ae13ef8fef28984393ac0d461c 100644 (file)
@@ -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
index 7ca96386a28ac7025382627b3922ca07331a87fb..2f7badadd30014d9f3e403714d6ce4ccf275c6b7 100644 (file)
@@ -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;    
index 0f2e55439b0b8637aa86ef0e412ab43dbc8a4be3..5a049597f44a44908b0c307f10581c82bfdcc4c6 100644 (file)
@@ -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);
index feffe96b6b574cc049b9e7d486a04b6e36312742..01fe09899a6991b167a8524f594f764dfd9989fd 100644 (file)
@@ -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 ==
index 7f775e575859e3f17e73a8c9bfe45c71be8671b9..a52c2de62700d02a5ce088d7eb6a9f5a35be8185 100644 (file)
@@ -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:
index c0613cbd3acca3ffd5f7bf4aa4152debc2e67819..453c305f1e5f270c8e5f65ccbbe96e43041e035b 100644 (file)
 #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, &params->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();
@@ -603,9 +854,342 @@ int key_size;
 
        return 0;
 
+       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;
 }
+
index 74be296acca4d11d7c2db7ac58376e6fec13577c..0df385b2cdbd61a435e1ce482811217e4e28ee85 100644 (file)
@@ -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);
                }
 
index b1f5d079753d1d0c6dedf1a1f3b0c97302add3de..ee066a0c3d55cc5422f6726d8b9620cc8d54e298 100644 (file)
@@ -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,