Browse Source

Internal TLS: Added support for parsing PKCS #8 formatted private keys

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.
Jouni Malinen 17 years ago
parent
commit
d952d16df4
2 changed files with 117 additions and 0 deletions
  1. 114 0
      src/crypto/crypto_internal.c
  2. 3 0
      wpa_supplicant/ChangeLog

+ 114 - 0
src/crypto/crypto_internal.c

@@ -22,6 +22,7 @@
 #include "aes.h"
 #include "aes.h"
 #include "tls/rsa.h"
 #include "tls/rsa.h"
 #include "tls/bignum.h"
 #include "tls/bignum.h"
+#include "tls/asn1.h"
 
 
 
 
 #ifdef EAP_TLS_FUNCS
 #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,
 struct crypto_private_key * crypto_private_key_import(const u8 *key,
 						      size_t len)
 						      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 *)
 	return (struct crypto_private_key *)
 		crypto_rsa_import_private_key(key, len);
 		crypto_rsa_import_private_key(key, len);
 }
 }

+ 3 - 0
wpa_supplicant/ChangeLog

@@ -8,6 +8,9 @@ ChangeLog for wpa_supplicant
 	* fixed the OpenSSL patches (0.9.8g and 0.9.9) for EAP-FAST to
 	* 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
 	  allow fallback to full handshake if server rejects PAC-Opaque
 	* added fragmentation support for EAP-TNC
 	* 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
 2008-02-22 - v0.6.3
 	* removed 'nai' and 'eappsk' network configuration variables that were
 	* removed 'nai' and 'eappsk' network configuration variables that were