Internal TLS: Added support for parsing PKCS #8 formatted private keys
authorJouni Malinen <j@w1.fi>
Mon, 2 Jun 2008 16:39:46 +0000 (19:39 +0300)
committerJouni Malinen <j@w1.fi>
Mon, 2 Jun 2008 16:39:46 +0000 (19:39 +0300)
The internal TLS implementation can now use both PKCS #1 RSA private key
and PKCS #8 encapsulated RSA private key. PKCS #8 encrypted private key is
not yet supported.

src/crypto/crypto_internal.c
wpa_supplicant/ChangeLog

index 719af1c..9324c6e 100644 (file)
@@ -22,6 +22,7 @@
 #include "aes.h"
 #include "tls/rsa.h"
 #include "tls/bignum.h"
+#include "tls/asn1.h"
 
 
 #ifdef EAP_TLS_FUNCS
@@ -434,9 +435,122 @@ struct crypto_public_key * crypto_public_key_import(const u8 *key, size_t len)
 }
 
 
+static struct crypto_private_key *
+crypto_pkcs8_key_import(const u8 *buf, size_t len)
+{
+       struct asn1_hdr hdr;
+       const u8 *pos, *end;
+       struct bignum *zero;
+       struct asn1_oid oid;
+       char obuf[80];
+
+       /* PKCS #8, Chapter 6 */
+
+       /* PrivateKeyInfo ::= SEQUENCE */
+       if (asn1_get_next(buf, len, &hdr) < 0 ||
+           hdr.class != ASN1_CLASS_UNIVERSAL ||
+           hdr.tag != ASN1_TAG_SEQUENCE) {
+               wpa_printf(MSG_DEBUG, "PKCS #8: Does not start with PKCS #8 "
+                          "header (SEQUENCE); assume PKCS #8 not used");
+               return NULL;
+       }
+       pos = hdr.payload;
+       end = pos + hdr.length;
+
+       /* version Version (Version ::= INTEGER) */
+       if (asn1_get_next(pos, end - pos, &hdr) < 0 ||
+           hdr.class != ASN1_CLASS_UNIVERSAL || hdr.tag != ASN1_TAG_INTEGER) {
+               wpa_printf(MSG_DEBUG, "PKCS #8: Expected INTEGER - found "
+                          "class %d tag 0x%x; assume PKCS #8 not used",
+                          hdr.class, hdr.tag);
+               return NULL;
+       }
+
+       zero = bignum_init();
+       if (zero == NULL)
+               return NULL;
+
+       if (bignum_set_unsigned_bin(zero, hdr.payload, hdr.length) < 0) {
+               wpa_printf(MSG_DEBUG, "PKCS #8: Failed to parse INTEGER");
+               bignum_deinit(zero);
+               return NULL;
+       }
+       pos = hdr.payload + hdr.length;
+
+       if (bignum_cmp_d(zero, 0) != 0) {
+               wpa_printf(MSG_DEBUG, "PKCS #8: Expected zero INTEGER in the "
+                          "beginning of private key; not found; assume "
+                          "PKCS #8 not used");
+               bignum_deinit(zero);
+               return NULL;
+       }
+       bignum_deinit(zero);
+
+       /* privateKeyAlgorithm PrivateKeyAlgorithmIdentifier
+        * (PrivateKeyAlgorithmIdentifier ::= AlgorithmIdentifier) */
+       if (asn1_get_next(pos, len, &hdr) < 0 ||
+           hdr.class != ASN1_CLASS_UNIVERSAL ||
+           hdr.tag != ASN1_TAG_SEQUENCE) {
+               wpa_printf(MSG_DEBUG, "PKCS #8: Expected SEQUENCE "
+                          "(AlgorithmIdentifier) - found class %d tag 0x%x; "
+                          "assume PKCS #8 not used",
+                          hdr.class, hdr.tag);
+               return NULL;
+       }
+
+       if (asn1_get_oid(hdr.payload, hdr.length, &oid, &pos)) {
+               wpa_printf(MSG_DEBUG, "PKCS #8: Failed to parse OID "
+                          "(algorithm); assume PKCS #8 not used");
+               return NULL;
+       }
+
+       asn1_oid_to_str(&oid, obuf, sizeof(obuf));
+       wpa_printf(MSG_DEBUG, "PKCS #8: algorithm=%s", obuf);
+
+       if (oid.len != 7 ||
+           oid.oid[0] != 1 /* iso */ ||
+           oid.oid[1] != 2 /* member-body */ ||
+           oid.oid[2] != 840 /* us */ ||
+           oid.oid[3] != 113549 /* rsadsi */ ||
+           oid.oid[4] != 1 /* pkcs */ ||
+           oid.oid[5] != 1 /* pkcs-1 */ ||
+           oid.oid[6] != 1 /* rsaEncryption */) {
+               wpa_printf(MSG_DEBUG, "PKCS #8: Unsupported private key "
+                          "algorithm %s", obuf);
+               return NULL;
+       }
+
+       pos = hdr.payload + hdr.length;
+
+       /* privateKey PrivateKey (PrivateKey ::= OCTET STRING) */
+       if (asn1_get_next(pos, end - pos, &hdr) < 0 ||
+           hdr.class != ASN1_CLASS_UNIVERSAL ||
+           hdr.tag != ASN1_TAG_OCTETSTRING) {
+               wpa_printf(MSG_DEBUG, "PKCS #8: Expected OCTETSTRING "
+                          "(privateKey) - found class %d tag 0x%x",
+                          hdr.class, hdr.tag);
+               return NULL;
+       }
+       wpa_printf(MSG_DEBUG, "PKCS #8: Try to parse RSAPrivateKey");
+
+       return (struct crypto_private_key *)
+               crypto_rsa_import_private_key(hdr.payload, hdr.length);
+}
+
+
 struct crypto_private_key * crypto_private_key_import(const u8 *key,
                                                      size_t len)
 {
+       struct crypto_private_key *res;
+
+       /* First, check for possible PKCS #8 encoding */
+       res = crypto_pkcs8_key_import(key, len);
+       if (res)
+               return res;
+
+       /* Not PKCS#8, so try to import PKCS #1 encoded RSA private key */
+       wpa_printf(MSG_DEBUG, "Trying to parse PKCS #1 encoded RSA private "
+                  "key");
        return (struct crypto_private_key *)
                crypto_rsa_import_private_key(key, len);
 }
index c1c68af..531a1be 100644 (file)
@@ -8,6 +8,9 @@ ChangeLog for wpa_supplicant
        * fixed the OpenSSL patches (0.9.8g and 0.9.9) for EAP-FAST to
          allow fallback to full handshake if server rejects PAC-Opaque
        * added fragmentation support for EAP-TNC
+       * added support for parsing PKCS #8 formatted private keys into the
+         internal TLS implementation (both PKCS #1 RSA key and PKCS #8
+         encapsulated RSA key can now be used)
 
 2008-02-22 - v0.6.3
        * removed 'nai' and 'eappsk' network configuration variables that were