summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNikos Mavrogiannopoulos <nmav@gnutls.org>2003-03-23 12:16:54 +0000
committerNikos Mavrogiannopoulos <nmav@gnutls.org>2003-03-23 12:16:54 +0000
commit1eff1dd92bb79997fb81a8dc53da7c73c4308e98 (patch)
tree3b708d93687bf7b9c694c2970df25e348c624883
parent50e430c625cd065dbc488ccd698fb8d7c9ac7bc4 (diff)
downloadgnutls-1eff1dd92bb79997fb81a8dc53da7c73c4308e98.tar.gz
* Added support for encoding and decoding PKCS #8 2.0 encrypted
RSA private keys.
-rw-r--r--NEWS3
-rw-r--r--includes/gnutls/x509.h3
-rw-r--r--lib/Makefile.am3
-rw-r--r--lib/gnutls_cipher_int.c7
-rw-r--r--lib/gnutls_cipher_int.h3
-rw-r--r--lib/gnutls_constate.c16
-rw-r--r--lib/gnutls_errors.c2
-rw-r--r--lib/x509/privkey_pkcs8.c620
-rw-r--r--lib/x509/x509.c4
-rw-r--r--lib/x509/x509.h2
10 files changed, 629 insertions, 34 deletions
diff --git a/NEWS b/NEWS
index 572fc175ed..260472b973 100644
--- 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
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, &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();
@@ -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,