diff options
author | Nikos Mavrogiannopoulos <nmav@gnutls.org> | 2003-03-23 19:29:29 +0000 |
---|---|---|
committer | Nikos Mavrogiannopoulos <nmav@gnutls.org> | 2003-03-23 19:29:29 +0000 |
commit | 0b5eab6ea262a3eb50a04234a0346d11ca706905 (patch) | |
tree | f34ce403c81062c32de9dd34f63f1aedc73beb0f | |
parent | d871b05901c30bce8e615b3b5ed1f8b88703a701 (diff) | |
download | gnutls-0b5eab6ea262a3eb50a04234a0346d11ca706905.tar.gz |
Allow for unencrypted PKCS #8 private keys.
-rw-r--r-- | includes/gnutls/x509.h | 8 | ||||
-rw-r--r-- | lib/x509/privkey.h | 6 | ||||
-rw-r--r-- | lib/x509/privkey_pkcs8.c | 115 | ||||
-rw-r--r-- | src/cli-gaa.c | 2 | ||||
-rw-r--r-- | src/cli.gaa | 2 |
5 files changed, 90 insertions, 43 deletions
diff --git a/includes/gnutls/x509.h b/includes/gnutls/x509.h index e79f8aba0a..995a3c765e 100644 --- a/includes/gnutls/x509.h +++ b/includes/gnutls/x509.h @@ -192,12 +192,18 @@ int gnutls_x509_crt_get_fingerprint(gnutls_x509_crt cert, /* Private key handling */ +typedef enum gnutls_privkey_pkcs8_flags { + GNUTLS_PKCS8_PLAIN=1, /* if set the private key will not + * be encrypted. + */ +} gnutls_privkey_pkcs8_flags; + int gnutls_x509_privkey_init(gnutls_x509_privkey * key); void gnutls_x509_privkey_deinit(gnutls_x509_privkey key); int gnutls_x509_privkey_import(gnutls_x509_privkey key, const gnutls_datum * data, gnutls_x509_crt_fmt format); 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 * pass, unsigned int flags); int gnutls_x509_privkey_import_rsa_raw(gnutls_x509_privkey privkey, const gnutls_datum *m, const gnutls_datum *e, const gnutls_datum *d, const gnutls_datum *p, const gnutls_datum *q, diff --git a/lib/x509/privkey.h b/lib/x509/privkey.h index e1111c75f7..4ba4e15fb5 100644 --- a/lib/x509/privkey.h +++ b/lib/x509/privkey.h @@ -1,3 +1,9 @@ +typedef enum gnutls_privkey_pkcs8_flags { + GNUTLS_PKCS8_PLAIN=1, /* if set the private key will not + * be encrypted. + */ +} gnutls_privkey_pkcs8_flags; + int gnutls_x509_privkey_import(gnutls_x509_privkey key, const gnutls_datum * data, gnutls_x509_crt_fmt format); ASN1_TYPE _gnutls_privkey_decode_pkcs1_rsa_key( const gnutls_datum *raw_key, diff --git a/lib/x509/privkey_pkcs8.c b/lib/x509/privkey_pkcs8.c index a1b3182677..c4f2e127b6 100644 --- a/lib/x509/privkey_pkcs8.c +++ b/lib/x509/privkey_pkcs8.c @@ -75,17 +75,19 @@ static int encrypt_data( const gnutls_datum* plain, gnutls_datum* key, gnutls_datum* encrypted); #define PEM_PKCS8 "ENCRYPTED PRIVATE KEY" +#define PEM_UNENCRYPTED_PKCS8 "PRIVATE KEY" /* * Encodes a PKCS #1 private key to a PKCS #8 private key - * info. The output will be allocated and stored into der. + * info. The output will be allocated and stored into der. Also + * the ASN1_TYPE of private key info will be returned. */ -static int encode_to_private_key_info( gnutls_x509_privkey pkey, gnutls_datum* der) +static int encode_to_private_key_info( gnutls_x509_privkey pkey, gnutls_datum* der, + ASN1_TYPE *pkey_info) { int result, size; opaque *data = NULL; - ASN1_TYPE pkcs8_asn = ASN1_TYPE_EMPTY; opaque null = 0; if (pkey->pk_algorithm != GNUTLS_PK_RSA) { @@ -95,7 +97,7 @@ static int encode_to_private_key_info( gnutls_x509_privkey pkey, gnutls_datum* d if ((result = asn1_create_element(_gnutls_get_pkix(), - "PKIX1.PrivateKeyInfo", &pkcs8_asn + "PKIX1.PrivateKeyInfo", pkey_info )) != ASN1_SUCCESS) { gnutls_assert(); result = _gnutls_asn2err(result); @@ -104,7 +106,7 @@ static int encode_to_private_key_info( gnutls_x509_privkey pkey, gnutls_datum* d /* Write the version. */ - result = asn1_write_value( pkcs8_asn, "version", &null, 1); + result = asn1_write_value( *pkey_info, "version", &null, 1); if (result != ASN1_SUCCESS) { gnutls_assert(); result = _gnutls_asn2err(result); @@ -114,14 +116,14 @@ static int encode_to_private_key_info( gnutls_x509_privkey pkey, gnutls_datum* d /* write the privateKeyAlgorithm * fields. (OID+NULL data) */ - result = asn1_write_value( pkcs8_asn, "privateKeyAlgorithm.algorithm", PKIX1_RSA_OID, 1); + result = asn1_write_value( *pkey_info, "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); + result = asn1_write_value( *pkey_info, "privateKeyAlgorithm.parameters", NULL, 0); if (result != ASN1_SUCCESS) { gnutls_assert(); result = _gnutls_asn2err(result); @@ -150,7 +152,7 @@ static int encode_to_private_key_info( gnutls_x509_privkey pkey, gnutls_datum* d goto error; } - result = asn1_write_value( pkcs8_asn, "privateKey", data, size); + result = asn1_write_value( *pkey_info, "privateKey", data, size); gnutls_afree( data); data = NULL; @@ -163,7 +165,7 @@ static int encode_to_private_key_info( gnutls_x509_privkey pkey, gnutls_datum* d /* Append an empty Attributes field. */ - result = asn1_write_value( pkcs8_asn, "attributes", NULL, 0); + result = asn1_write_value( *pkey_info, "attributes", NULL, 0); if (result != ASN1_SUCCESS) { gnutls_assert(); result = _gnutls_asn2err(result); @@ -173,7 +175,7 @@ static int encode_to_private_key_info( gnutls_x509_privkey pkey, gnutls_datum* d /* DER Encode the generated private key info. */ size = 0; - result = asn1_der_coding( pkcs8_asn, "", NULL, &size, NULL); + result = asn1_der_coding( *pkey_info, "", NULL, &size, NULL); if (result != ASN1_MEM_ERROR) { gnutls_assert(); result = _gnutls_asn2err(result); @@ -189,19 +191,17 @@ static int encode_to_private_key_info( gnutls_x509_privkey pkey, gnutls_datum* d return GNUTLS_E_MEMORY_ERROR; } - result = asn1_der_coding( pkcs8_asn, "", der->data, &size, NULL); + result = asn1_der_coding( *pkey_info, "", 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); + asn1_delete_structure( pkey_info); if (data != NULL) { gnutls_afree(data); } return result; @@ -286,7 +286,7 @@ static ASN1_TYPE encode_to_pkcs8_key( const gnutls_datum *raw_key, * @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 + * @flags: an ORed sequence of gnutls_privkey_pkcs8_flags * @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) * @@ -296,7 +296,8 @@ static ASN1_TYPE encode_to_pkcs8_key( const gnutls_datum *raw_key, * GNUTLS_E_SHORT_MEMORY_BUFFER will be returned. * * If the structure is PEM encoded, it will have a header - * of "BEGIN ENCRYPTED PRIVATE KEY". + * of "BEGIN ENCRYPTED PRIVATE KEY" or "BEGIN PRIVATE KEY" if + * encryption is not used. * * In case of failure a negative value will be returned, and * 0 on success. @@ -306,31 +307,44 @@ 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) { -ASN1_TYPE pkcs8_asn; +ASN1_TYPE pkcs8_asn, pkey_info; int ret; gnutls_datum tmp; /* Get the private key info */ - ret = encode_to_private_key_info( key, &tmp); + ret = encode_to_private_key_info( key, &tmp, &pkey_info); if ( ret < 0) { gnutls_assert(); return ret; } + if (!(flags & GNUTLS_PKCS8_PLAIN) || password == NULL) { - pkcs8_asn = encode_to_pkcs8_key( &tmp, password, flags); - _gnutls_free_datum( &tmp); + asn1_delete_structure( &pkey_info); /* we don't need it */ - if (pkcs8_asn == NULL) { - gnutls_assert(); - return GNUTLS_E_ASN1_GENERIC_ERROR; + pkcs8_asn = encode_to_pkcs8_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); + + } else { + _gnutls_free_datum( &tmp); + + ret = _gnutls_x509_export_int( pkey_info, format, PEM_UNENCRYPTED_PKCS8, + *output_data_size, output_data, output_data_size); + + asn1_delete_structure( &pkey_info); } - 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; } @@ -545,21 +559,24 @@ static ASN1_TYPE decode_private_key_info( const gnutls_datum* der, gnutls_x509_p * @key: The structure to store the parsed key * @data: The DER or PEM encoded certificate. * @format: One of DER or PEM - * @password: the password to decrypt the key + * @password: the password to decrypt the key (if it is encrypted) + * @flags: an ORed sequence of gnutls_privkey_pkcs8_flags * * 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'. * - * If the Certificate is PEM encoded it should have a header of "ENCRYPTED PRIVATE KEY". + * If the Certificate is PEM encoded it should have a header of "ENCRYPTED PRIVATE KEY", + * or "PRIVATE KEY". You only need to specify the flags if the key is DER encoded. * * Returns 0 on success. * **/ int gnutls_x509_privkey_import_pkcs8(gnutls_x509_privkey key, const gnutls_datum * data, - gnutls_x509_crt_fmt format, char * password) + gnutls_x509_crt_fmt format, char * password, unsigned int flags) { int result = 0, need_free = 0; gnutls_datum _data = { data->data, data->size }; + int encrypted; key->pk_algorithm = GNUTLS_PK_UNKNOWN; @@ -567,25 +584,39 @@ int gnutls_x509_privkey_import_pkcs8(gnutls_x509_privkey key, const gnutls_datum */ if (format == GNUTLS_X509_FMT_PEM) { opaque *out; - - /* Try the first header */ - result = _gnutls_fbase64_decode(PEM_PKCS8, data->data, data->size, - &out); - if (result <= 0) { - if (result==0) result = GNUTLS_E_INTERNAL_ERROR; - gnutls_assert(); - return result; - } + /* Try the first header + */ + result = _gnutls_fbase64_decode(PEM_UNENCRYPTED_PKCS8, data->data, data->size, + &out); + encrypted = 0; + if (result < 0) { /* Try the encrypted header + */ + result = _gnutls_fbase64_decode(PEM_PKCS8, data->data, data->size, + &out); + + if (result <= 0) { + if (result==0) result = GNUTLS_E_INTERNAL_ERROR; + gnutls_assert(); + return result; + } + + encrypted = 1; + } + _data.data = out; _data.size = result; need_free = 1; } + if (flags & GNUTLS_PKCS8_PLAIN || password == NULL) { + key->key = decode_private_key_info( &_data, key); + } else { /* encrypted. */ + key->key = decode_pkcs8_key( &_data, password, key); + } - key->key = decode_pkcs8_key( &_data, password, key); if (key->key == NULL) { gnutls_assert(); result = GNUTLS_E_ASN1_DER_ERROR; @@ -1061,6 +1092,10 @@ static int generate_key( const char* password, unsigned int flags, opaque rnd[2]; int ret; + /* We should use the flags here to use different + * encryption algorithms etc. + */ + _gnutls_get_random( rnd, 2, GNUTLS_STRONG_RANDOM); /* generate salt */ diff --git a/src/cli-gaa.c b/src/cli-gaa.c index 05257dc33c..a223a2f4d3 100644 --- a/src/cli-gaa.c +++ b/src/cli-gaa.c @@ -130,7 +130,7 @@ void gaa_help(void) __gaa_helpsingle('r', "resume", "", "Connect, establish a session. Connect again and resume this session."); __gaa_helpsingle('s', "starttls", "", "Connect, establish a plain session and start TLS when EOF is sent from the keyboard."); __gaa_helpsingle(0, "crlf", "", "Send CR LF instead of LF."); - __gaa_helpsingle(0, "x509fmtder", "", "Use DER format for certificates"); + __gaa_helpsingle(0, "x509fmtder", "", "Use DER format for certificates to read from."); __gaa_helpsingle('f', "fingerprint", "", "Send the openpgp fingerprint, instead of the key."); __gaa_helpsingle(0, "disable-extensions", "", "Disable all the TLS extensions."); __gaa_helpsingle(0, "xml", "", "Print the certificate information in XML format."); diff --git a/src/cli.gaa b/src/cli.gaa index acc583cb98..9e1dfb1a6c 100644 --- a/src/cli.gaa +++ b/src/cli.gaa @@ -21,7 +21,7 @@ option (s, starttls) { $starttls = 1 } "Connect, establish a plain session and s option (crlf) { $crlf = 1 } "Send CR LF instead of LF." #int fmtder; -option (x509fmtder) { $fmtder = 1 } "Use DER format for certificates" +option (x509fmtder) { $fmtder = 1 } "Use DER format for certificates to read from." #int fingerprint; option (f, fingerprint) { $fingerprint = 1 } "Send the openpgp fingerprint, instead of the key." |