diff options
Diffstat (limited to 'security/nss/lib/ssl')
-rw-r--r-- | security/nss/lib/ssl/nsskea.c | 6 | ||||
-rw-r--r-- | security/nss/lib/ssl/preenc.h | 94 | ||||
-rw-r--r-- | security/nss/lib/ssl/prelib.c | 197 | ||||
-rw-r--r-- | security/nss/lib/ssl/ssl.h | 2 | ||||
-rw-r--r-- | security/nss/lib/ssl/ssl3con.c | 1005 | ||||
-rw-r--r-- | security/nss/lib/ssl/ssl3prot.h | 17 | ||||
-rw-r--r-- | security/nss/lib/ssl/sslauth.c | 3 | ||||
-rw-r--r-- | security/nss/lib/ssl/sslcon.c | 2 | ||||
-rw-r--r-- | security/nss/lib/ssl/sslenum.c | 5 | ||||
-rw-r--r-- | security/nss/lib/ssl/sslimpl.h | 16 | ||||
-rw-r--r-- | security/nss/lib/ssl/sslinfo.c | 5 | ||||
-rw-r--r-- | security/nss/lib/ssl/sslproto.h | 6 | ||||
-rw-r--r-- | security/nss/lib/ssl/sslsecur.c | 7 | ||||
-rw-r--r-- | security/nss/lib/ssl/sslsnce.c | 6 | ||||
-rw-r--r-- | security/nss/lib/ssl/sslsock.c | 3 | ||||
-rw-r--r-- | security/nss/lib/ssl/sslt.h | 6 |
16 files changed, 1304 insertions, 76 deletions
diff --git a/security/nss/lib/ssl/nsskea.c b/security/nss/lib/ssl/nsskea.c index beafc506e..b61ac71e4 100644 --- a/security/nss/lib/ssl/nsskea.c +++ b/security/nss/lib/ssl/nsskea.c @@ -58,6 +58,12 @@ NSS_FindCertKEAType(CERTCertificate * cert) case SEC_OID_PKCS1_RSA_ENCRYPTION: keaType = kt_rsa; break; + case SEC_OID_MISSI_KEA_DSS_OLD: + case SEC_OID_MISSI_KEA_DSS: + case SEC_OID_MISSI_DSS_OLD: + case SEC_OID_MISSI_DSS: + keaType = kt_fortezza; + break; case SEC_OID_X942_DIFFIE_HELMAN_KEY: keaType = kt_dh; break; diff --git a/security/nss/lib/ssl/preenc.h b/security/nss/lib/ssl/preenc.h index f7c9093cb..9b6d3104a 100644 --- a/security/nss/lib/ssl/preenc.h +++ b/security/nss/lib/ssl/preenc.h @@ -1,7 +1,8 @@ /* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil -*- */ /* - * Fortezza support is removed. + * Functions and types used by https servers to send (download) pre-encrypted + * files over SSL connections that use Fortezza ciphersuites. * * ***** BEGIN LICENSE BLOCK ***** * Version: MPL 1.1/GPL 2.0/LGPL 2.1 @@ -40,11 +41,6 @@ * ***** END LICENSE BLOCK ***** */ /* $Id$ */ -/* Fortezza support is removed. - * This file remains so that old programs will continue to compile, - * But this functionality is no longer supported or implemented. - */ - #include "seccomon.h" #include "prio.h" @@ -52,44 +48,53 @@ typedef struct PEHeaderStr PEHeader; #define PE_MIME_TYPE "application/pre-encrypted" + +/* + * unencrypted header. The 'top' half of this header is generic. The union + * is type specific, and may include bulk cipher type information + * (Fortezza supports only Fortezza Bulk encryption). Only fortezza + * pre-encrypted is defined. + */ typedef struct PEFortezzaHeaderStr PEFortezzaHeader; typedef struct PEFortezzaGeneratedHeaderStr PEFortezzaGeneratedHeader; typedef struct PEFixedKeyHeaderStr PEFixedKeyHeader; typedef struct PERSAKeyHeaderStr PERSAKeyHeader; struct PEFortezzaHeaderStr { - unsigned char key[12]; - unsigned char iv[24]; - unsigned char hash[20]; - unsigned char serial[8]; + unsigned char key[12]; /* Ks wrapped MEK */ + unsigned char iv[24]; /* iv for this MEK */ + unsigned char hash[20]; /* SHA hash of file */ + unsigned char serial[8]; /* serial number of the card that owns + * Ks */ }; struct PEFortezzaGeneratedHeaderStr { - unsigned char key[12]; - unsigned char iv[24]; - unsigned char hash[20]; - unsigned char Ra[128]; - unsigned char Y[128]; + unsigned char key[12]; /* TEK wrapped MEK */ + unsigned char iv[24]; /* iv for this MEK */ + unsigned char hash[20]; /* SHA hash of file */ + unsigned char Ra[128]; /* RA to generate TEK */ + unsigned char Y[128]; /* Y to generate TEK */ }; struct PEFixedKeyHeaderStr { - unsigned char pkcs11Mech[4]; - unsigned char labelLen[2]; - unsigned char keyIDLen[2]; - unsigned char ivLen[2]; - unsigned char keyLen[2]; - unsigned char data[1]; + unsigned char pkcs11Mech[4]; /* Symetric key operation */ + unsigned char labelLen[2]; /* length of the token label */ + unsigned char keyIDLen[2]; /* length of the token Key ID */ + unsigned char ivLen[2]; /* length of IV */ + unsigned char keyLen[2]; /* length of key (DES3_ECB encrypted) */ + unsigned char data[1]; /* start of data */ }; struct PERSAKeyHeaderStr { - unsigned char pkcs11Mech[4]; - unsigned char issuerLen[2]; - unsigned char serialLen[2]; - unsigned char ivLen[2]; - unsigned char keyLen[2]; - unsigned char data[1]; + unsigned char pkcs11Mech[4]; /* Symetric key operation */ + unsigned char issuerLen[2]; /* length of cert issuer */ + unsigned char serialLen[2]; /* length of the cert serial */ + unsigned char ivLen[2]; /* length of IV */ + unsigned char keyLen[2]; /* length of key (RSA encrypted) */ + unsigned char data[1]; /* start of data */ }; +/* macros to get at the variable length data fields */ #define PEFIXED_Label(header) (header->data) #define PEFIXED_KeyID(header) (&header->data[GetInt2(header->labelLen)]) #define PEFIXED_IV(header) (&header->data[GetInt2(header->labelLen)\ @@ -103,10 +108,10 @@ struct PERSAKeyHeaderStr { #define PERSA_Key(header) (&header->data[GetInt2(header->issuerLen)\ +GetInt2(header->serialLen)+GetInt2(header->keyLen)]) struct PEHeaderStr { - unsigned char magic [2]; - unsigned char len [2]; - unsigned char type [2]; - unsigned char version[2]; + unsigned char magic [2]; /* always 0xC0DE */ + unsigned char len [2]; /* length of PEHeader */ + unsigned char type [2]; /* FORTEZZA, DIFFIE-HELMAN, RSA */ + unsigned char version[2]; /* version number: 1.0 */ union { PEFortezzaHeader fortezza; PEFortezzaGeneratedHeader g_fortezza; @@ -119,9 +124,12 @@ struct PEHeaderStr { #define PE_INTRO_LEN 4 #define PE_BASE_HEADER_LEN 8 -#define PRE_BLOCK_SIZE 8 +#define PRE_BLOCK_SIZE 8 /* for decryption blocks */ +/* + * Platform neutral encode/decode macros. + */ #define GetInt2(c) ((c[0] << 8) | c[1]) #define GetInt4(c) (((unsigned long)c[0] << 24)|((unsigned long)c[1] << 16)\ |((unsigned long)c[2] << 8)| ((unsigned long)c[3])) @@ -129,18 +137,28 @@ struct PEHeaderStr { #define PutInt4(c,i) ((c[0]=((i) >> 24) & 0xff),(c[1]=((i) >> 16) & 0xff),\ (c[2] = ((i) >> 8) & 0xff), (c[3] = (i) & 0xff)) +/* + * magic numbers. + */ #define PRE_MAGIC 0xc0de #define PRE_VERSION 0x1010 -#define PRE_FORTEZZA_FILE 0x00ff -#define PRE_FORTEZZA_STREAM 0x00f5 -#define PRE_FORTEZZA_GEN_STREAM 0x00f6 -#define PRE_FIXED_FILE 0x000f -#define PRE_RSA_FILE 0x001f -#define PRE_FIXED_STREAM 0x0005 +#define PRE_FORTEZZA_FILE 0x00ff /* pre-encrypted file on disk */ +#define PRE_FORTEZZA_STREAM 0x00f5 /* pre-encrypted file in stream */ +#define PRE_FORTEZZA_GEN_STREAM 0x00f6 /* Generated pre-encrypted file */ +#define PRE_FIXED_FILE 0x000f /* fixed key on disk */ +#define PRE_RSA_FILE 0x001f /* RSA in file */ +#define PRE_FIXED_STREAM 0x0005 /* fixed key in stream */ + +/* + * internal implementation info + */ + +/* convert an existing stream header to a version with local parameters */ PEHeader *SSL_PreencryptedStreamToFile(PRFileDesc *fd, PEHeader *, int *headerSize); +/* convert an existing file header to one suitable for streaming out */ PEHeader *SSL_PreencryptedFileToStream(PRFileDesc *fd, PEHeader *, int *headerSize); diff --git a/security/nss/lib/ssl/prelib.c b/security/nss/lib/ssl/prelib.c index c63483924..b24399b98 100644 --- a/security/nss/lib/ssl/prelib.c +++ b/security/nss/lib/ssl/prelib.c @@ -50,18 +50,205 @@ #include "preenc.h" #include "pk11func.h" +static unsigned char fromHex(char x) { + if ((x >= '0') && (x <= '9')) return x-'0'; + if ((x >= 'a') && (x <= 'f')) return x-'a'+10; + return x-'A'+10; +} + PEHeader *SSL_PreencryptedStreamToFile(PRFileDesc *fd, PEHeader *inHeader, - int *headerSize) + int *headerSize) { - PORT_SetError(PR_NOT_IMPLEMENTED_ERROR); - return NULL; + PK11SymKey *key, *tek, *Ks; + sslSocket *ss; + PK11SlotInfo *slot; + CK_TOKEN_INFO info; + int oldHeaderSize; + PEHeader *header; + SECStatus rv; + SECItem item; + int i; + + if (fd == NULL) { + /* XXX set an error */ + return NULL; + } + + ss = ssl_FindSocket(fd); + if (ss == NULL) { + return NULL; + } + + PORT_Assert(ss->ssl3 != NULL); + if (ss->ssl3 == NULL) { + return NULL; + } + + if (GetInt2(inHeader->magic) != PRE_MAGIC) { + return NULL; + } + + oldHeaderSize = GetInt2(inHeader->len); + header = (PEHeader *) PORT_ZAlloc(oldHeaderSize); + if (header == NULL) { + return NULL; + } + + switch (GetInt2(inHeader->type)) { + case PRE_FORTEZZA_FILE: + case PRE_FORTEZZA_GEN_STREAM: + case PRE_FIXED_FILE: + case PRE_RSA_FILE: + default: + *headerSize = oldHeaderSize; + PORT_Memcpy(header,inHeader,oldHeaderSize); + return header; + + case PRE_FORTEZZA_STREAM: + *headerSize = PE_BASE_HEADER_LEN + sizeof(PEFortezzaHeader); + PutInt2(header->magic,PRE_MAGIC); + PutInt2(header->len,*headerSize); + PutInt2(header->type, PRE_FORTEZZA_FILE); + PORT_Memcpy(header->version,inHeader->version,sizeof(header->version)); + PORT_Memcpy(header->u.fortezza.hash,inHeader->u.fortezza.hash, + sizeof(header->u.fortezza.hash)); + PORT_Memcpy(header->u.fortezza.iv,inHeader->u.fortezza.iv, + sizeof(header->u.fortezza.iv)); + + /* get the kea context from the session */ + tek = ss->ssl3->fortezza.tek; + if (tek == NULL) { + PORT_Free(header); + return NULL; + } + + + /* get the slot and the serial number */ + slot = PK11_GetSlotFromKey(tek); + if (slot == NULL) { + PORT_Free(header); + return NULL; + } + rv = PK11_GetTokenInfo(slot,&info); + if (rv != SECSuccess) { + PORT_Free(header); + PK11_FreeSlot(slot); + return NULL; + } + + /* Look up the Token Fixed Key */ + Ks = PK11_FindFixedKey(slot, CKM_SKIPJACK_WRAP, NULL, ss->pkcs11PinArg); + PK11_FreeSlot(slot); + if (Ks == NULL) { + PORT_Free(header); + return NULL; + } + + /* unwrap the key with the TEK */ + item.data = inHeader->u.fortezza.key; + item.len = sizeof(inHeader->u.fortezza.key); + key = PK11_UnwrapSymKey(tek,CKM_SKIPJACK_WRAP, + NULL, &item, CKM_SKIPJACK_CBC64, CKA_DECRYPT, 0); + if (key == NULL) { + PORT_Free(header); + PK11_FreeSymKey(Ks); + return NULL; + } + + /* rewrap with the local Ks */ + item.data = header->u.fortezza.key; + item.len = sizeof(header->u.fortezza.key); + rv = PK11_WrapSymKey(CKM_SKIPJACK_WRAP, NULL, Ks, key, &item); + PK11_FreeSymKey(Ks); + PK11_FreeSymKey(key); + if (rv != SECSuccess) { + PORT_Free(header); + return NULL; + } + + /* copy our local serial number into header */ + for (i=0; i < sizeof(header->u.fortezza.serial); i++) { + header->u.fortezza.serial[i] = + (fromHex(info.serialNumber[i*2]) << 4) | + fromHex(info.serialNumber[i*2 + 1]); + } + break; + case PRE_FIXED_STREAM: + /* not implemented yet */ + PORT_Free(header); + return NULL; + } + + return(header); } +/* + * this one needs to allocate space and work for RSA & FIXED key files as well + */ PEHeader *SSL_PreencryptedFileToStream(PRFileDesc *fd, PEHeader *header, int *headerSize) { - PORT_SetError(PR_NOT_IMPLEMENTED_ERROR); - return NULL; + PK11SymKey *key, *tek, *Ks; + sslSocket *ss; + PK11SlotInfo *slot; + SECStatus rv; + SECItem item; + + *headerSize = 0; /* hack */ + + if (fd == NULL) { + /* XXX set an error */ + return NULL; + } + + ss = ssl_FindSocket(fd); + if (ss == NULL) { + return NULL; + } + + PORT_Assert(ss->ssl3 != NULL); + if (ss->ssl3 == NULL) { + return NULL; + } + + /* get the kea context from the session */ + tek = ss->ssl3->fortezza.tek; + if (tek == NULL) { + return NULL; + } + + slot = PK11_GetSlotFromKey(tek); + if (slot == NULL) return NULL; + Ks = PK11_FindFixedKey(slot, CKM_SKIPJACK_WRAP, NULL, PK11_GetWindow(tek)); + PK11_FreeSlot(slot); + if (Ks == NULL) return NULL; + + + /* unwrap with the local Ks */ + item.data = header->u.fortezza.key; + item.len = sizeof(header->u.fortezza.key); + /* rewrap the key with the TEK */ + key = PK11_UnwrapSymKey(Ks,CKM_SKIPJACK_WRAP, + NULL, &item, CKM_SKIPJACK_CBC64, CKA_DECRYPT, 0); + if (key == NULL) { + PK11_FreeSymKey(Ks); + return NULL; + } + + rv = PK11_WrapSymKey(CKM_SKIPJACK_WRAP, NULL, tek, key, &item); + PK11_FreeSymKey(Ks); + PK11_FreeSymKey(key); + if (rv != SECSuccess) { + return NULL; + } + + /* copy over our local serial number */ + PORT_Memset(header->u.fortezza.serial,0,sizeof(header->u.fortezza.serial)); + + /* change type to stream */ + PutInt2(header->type, PRE_FORTEZZA_STREAM); + + return(header); } diff --git a/security/nss/lib/ssl/ssl.h b/security/nss/lib/ssl/ssl.h index e22c70504..f6ab20af7 100644 --- a/security/nss/lib/ssl/ssl.h +++ b/security/nss/lib/ssl/ssl.h @@ -190,7 +190,7 @@ SSL_IMPORT SECStatus SSL_SecurityStatus(PRFileDesc *fd, int *on, char **cipher, #define SSL_SECURITY_STATUS_OFF 0 #define SSL_SECURITY_STATUS_ON_HIGH 1 #define SSL_SECURITY_STATUS_ON_LOW 2 -#define SSL_SECURITY_STATUS_FORTEZZA 3 /* NO LONGER SUPPORTED */ +#define SSL_SECURITY_STATUS_FORTEZZA 3 /* ** Return the certificate for our SSL peer. If the client calls this diff --git a/security/nss/lib/ssl/ssl3con.c b/security/nss/lib/ssl/ssl3con.c index 669060bc2..1e7f7411a 100644 --- a/security/nss/lib/ssl/ssl3con.c +++ b/security/nss/lib/ssl/ssl3con.c @@ -109,6 +109,7 @@ static ssl3CipherSuiteCfg cipherSuites[ssl_V3_SUITES_IMPLEMENTED] = { #endif /* NSS_ENABLE_ECC */ { TLS_RSA_WITH_AES_256_CBC_SHA, SSL_NOT_ALLOWED, PR_FALSE,PR_FALSE}, + { SSL_FORTEZZA_DMS_WITH_RC4_128_SHA, SSL_NOT_ALLOWED, PR_TRUE, PR_FALSE}, #ifdef NSS_ENABLE_ECC { TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA, SSL_NOT_ALLOWED, PR_FALSE,PR_FALSE}, { TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA, SSL_NOT_ALLOWED, PR_FALSE,PR_FALSE}, @@ -135,6 +136,7 @@ static ssl3CipherSuiteCfg cipherSuites[ssl_V3_SUITES_IMPLEMENTED] = { { SSL_RSA_FIPS_WITH_3DES_EDE_CBC_SHA, SSL_NOT_ALLOWED, PR_TRUE, PR_FALSE}, { SSL_RSA_WITH_3DES_EDE_CBC_SHA, SSL_NOT_ALLOWED, PR_TRUE, PR_FALSE}, + { SSL_FORTEZZA_DMS_WITH_FORTEZZA_CBC_SHA, SSL_NOT_ALLOWED, PR_TRUE, PR_FALSE}, { SSL_DHE_RSA_WITH_DES_CBC_SHA, SSL_NOT_ALLOWED, PR_FALSE,PR_FALSE}, { SSL_DHE_DSS_WITH_DES_CBC_SHA, SSL_NOT_ALLOWED, PR_FALSE,PR_FALSE}, @@ -150,6 +152,7 @@ static ssl3CipherSuiteCfg cipherSuites[ssl_V3_SUITES_IMPLEMENTED] = { { SSL_RSA_EXPORT_WITH_RC4_40_MD5, SSL_NOT_ALLOWED, PR_TRUE, PR_FALSE}, { SSL_RSA_EXPORT_WITH_RC2_CBC_40_MD5, SSL_NOT_ALLOWED, PR_TRUE, PR_FALSE}, + { SSL_FORTEZZA_DMS_WITH_NULL_SHA, SSL_NOT_ALLOWED, PR_TRUE, PR_FALSE}, #ifdef NSS_ENABLE_ECC { TLS_ECDH_RSA_WITH_NULL_SHA, SSL_NOT_ALLOWED, PR_FALSE, PR_FALSE}, { TLS_ECDH_ECDSA_WITH_NULL_SHA, SSL_NOT_ALLOWED, PR_FALSE, PR_FALSE}, @@ -174,6 +177,9 @@ static const /*SSL3ClientCertificateType */ uint8 certificate_types [] = { #endif /* NSS_ENABLE_ECC */ }; +static const /*SSL3ClientCertificateType */ uint8 fortezza_certificate_types [] = { + ct_Fortezza, +}; /* * make sure there is room in the write buffer for padding and @@ -211,13 +217,13 @@ static const ssl3BulkCipherDef bulk_cipher_defs[] = { {cipher_3des, calg_3des, 24, 24, type_block, 8, 8, kg_strong}, {cipher_des40, calg_des, 8, 5, type_block, 8, 8, kg_export}, {cipher_idea, calg_idea, 16, 16, type_block, 8, 8, kg_strong}, + {cipher_fortezza, calg_fortezza, 10, 10, type_block, 24, 8, kg_null}, {cipher_aes_128, calg_aes, 16, 16, type_block, 16,16, kg_strong}, {cipher_aes_256, calg_aes, 32, 32, type_block, 16,16, kg_strong}, {cipher_missing, calg_null, 0, 0, type_stream, 0, 0, kg_null}, }; -static const ssl3KEADef kea_defs[] = -{ /* indexed by SSL3KeyExchangeAlgorithm */ +static const ssl3KEADef kea_defs[] = { /* indexed by SSL3KeyExchangeAlgorithm */ /* kea exchKeyType signKeyType is_limited limit tls_keygen */ {kea_null, kt_null, sign_null, PR_FALSE, 0, PR_FALSE}, {kea_rsa, kt_rsa, sign_rsa, PR_FALSE, 0, PR_FALSE}, @@ -233,6 +239,7 @@ static const ssl3KEADef kea_defs[] = {kea_dhe_rsa_export, kt_dh, sign_rsa, PR_TRUE, 512, PR_FALSE}, {kea_dh_anon, kt_dh, sign_null, PR_FALSE, 0, PR_FALSE}, {kea_dh_anon_export, kt_dh, sign_null, PR_TRUE, 512, PR_FALSE}, + {kea_fortezza, kt_fortezza, sign_dsa, PR_FALSE, 0, PR_FALSE}, {kea_rsa_fips, kt_rsa, sign_rsa, PR_FALSE, 0, PR_TRUE }, #ifdef NSS_ENABLE_ECC {kea_ecdh_ecdsa, kt_ecdh, sign_ecdsa, PR_FALSE, 0, PR_FALSE}, @@ -243,8 +250,7 @@ static const ssl3KEADef kea_defs[] = }; /* must use ssl_LookupCipherSuiteDef to access */ -static const ssl3CipherSuiteDef cipher_suite_defs[] = -{ +static const ssl3CipherSuiteDef cipher_suite_defs[] = { /* cipher_suite bulk_cipher_alg mac_alg key_exchange_alg */ {SSL_NULL_WITH_NULL_NULL, cipher_null, mac_null, kea_null}, @@ -292,6 +298,10 @@ static const ssl3CipherSuiteDef cipher_suite_defs[] = {SSL_DH_ANON_3DES_CBC_SHA, cipher_3des, mac_sha, kea_dh_anon}, #endif + {SSL_FORTEZZA_DMS_WITH_NULL_SHA, cipher_null, mac_sha, kea_fortezza}, + {SSL_FORTEZZA_DMS_WITH_FORTEZZA_CBC_SHA, + cipher_fortezza, mac_sha, kea_fortezza}, + {SSL_FORTEZZA_DMS_WITH_RC4_128_SHA, cipher_rc4, mac_sha, kea_fortezza}, /* New TLS cipher suites */ {TLS_RSA_WITH_AES_128_CBC_SHA, cipher_aes_128, mac_sha, kea_rsa}, @@ -352,16 +362,14 @@ typedef struct SSLCipher2MechStr { CK_MECHANISM_TYPE cmech; } SSLCipher2Mech; -/* indexed by type SSLCipherAlgorithm */ static const SSLCipher2Mech alg2Mech[] = { - /* calg, cmech */ { calg_null , (CK_MECHANISM_TYPE)0x80000000L }, { calg_rc4 , CKM_RC4 }, { calg_rc2 , CKM_RC2_CBC }, { calg_des , CKM_DES_CBC }, { calg_3des , CKM_DES3_CBC }, { calg_idea , CKM_IDEA_CBC }, - { calg_fortezza , CKM_SKIPJACK_CBC64 }, + { calg_fortezza , CKM_SKIPJACK_CBC64 }, { calg_aes , CKM_AES_CBC }, /* { calg_init , (CK_MECHANISM_TYPE)0x7fffffffL } */ }; @@ -393,6 +401,7 @@ const char * const ssl3_cipherName[] = { "3DES-EDE-CBC", "DES-CBC-40", "IDEA-CBC", + "FORTEZZA", "AES-128", "AES-256", "missing" @@ -829,6 +838,7 @@ ssl3_SignHashes(SSL3Hashes *hash, SECKEYPrivateKey *key, SECItem *buf, hashItem.len = sizeof(SSL3Hashes); break; case dsaKey: + case fortezzaKey: doDerEncode = isTLS; hashItem.data = hash->sha; hashItem.len = sizeof(hash->sha); @@ -901,6 +911,7 @@ ssl3_VerifySignedHashes(SSL3Hashes *hash, CERTCertificate *cert, hashItem.len = sizeof(SSL3Hashes); break; case dsaKey: + case fortezzaKey: hashItem.data = hash->sha; hashItem.len = sizeof(hash->sha); if (isTLS) { @@ -1201,6 +1212,30 @@ done: } #endif /* NSS_ENABLE_ECC */ +/* Caller must set hiLevel error code. */ +static SECStatus +ssl3_ComputeFortezzaPublicKeyHash(SECItem publicValue, unsigned char * hash) +{ + PK11Context *sha = NULL; + SECStatus rv = SECFailure; + unsigned int outLen; + + sha = PK11_CreateDigestContext(SEC_OID_SHA1); + if (sha == NULL) { + return rv; /* Caller must set hiLevel error code. */ + } + + rv = PK11_DigestBegin(sha); + rv |= PK11_DigestOp(sha, (unsigned char *)publicValue.data, publicValue.len); + rv |= PK11_DigestFinal(sha, hash, &outLen, SHA1_LENGTH); + PORT_Assert(rv != SECSuccess || outLen == SHA1_LENGTH); + if (rv != SECSuccess) + rv = SECFailure; + PK11_DestroyContext(sha, PR_TRUE); + + return rv; +} + static void ssl3_BumpSequenceNumber(SSL3SequenceNumber *num) @@ -1678,9 +1713,10 @@ ssl3_SendRecord( sslSocket * ss, } } - /* This variable records the actual size of the buffer allocated above. - * Some algorithms may expand the number of bytes needed to send data. - * If we only supply the output buffer with the same number + /* This variable records + * the actual size of the buffer we allocated above. Some + * algorithms (FORTEZZA) will expand the number of bytes it needs to + * send data. If we only supply the output buffer with the same number * of bytes as the input buffer, we will fail. */ bufSize = contentLen + SSL3_BUFFER_FUDGE; @@ -1958,6 +1994,7 @@ ssl3_HandleNoCertificate(sslSocket *ss) ** ssl3_HandleClientHello <- ** ssl3_HandleV2ClientHello <- ** ssl3_HandleCertificateVerify <- +** ssl3_HandleFortezzaClientKeyExchange <- ** ssl3_HandleClientKeyExchange <- ** ssl3_HandleCertificate <- ** ssl3_HandleFinished <- @@ -2272,7 +2309,9 @@ ssl3_GenerateSessionKeys(sslSocket *ss, const PK11SymKey *pms) void * pwArg = ss->pkcs11PinArg; PRBool isTLS = (PRBool)(kea_def->tls_keygen || (pwSpec->version > SSL_LIBRARY_VERSION_3_0)); - PRBool skipKeysAndIVs = (PRBool)(cipher_def->calg == calg_null); + PRBool skipKeysAndIVs = (PRBool) + ((cipher_def->calg == calg_fortezza) || + (cipher_def->calg == calg_null)); /* * Whenever isDH is true, we need to use CKM_TLS_MASTER_KEY_DERIVE_DH * which, unlike CKM_TLS_MASTER_KEY_DERIVE, converts arbitrary size @@ -2960,7 +2999,8 @@ ssl3_SendClientHello(sslSocket *ss) * make sure the token that holds the master secret still exists ... * If we previously did client-auth, make sure that the token that holds * the private key still exists, is logged in, hasn't been removed, etc. - */ + * Also for fortezza, make sure that the card that holds the session keys + * exist as well... */ if (sid) { PK11SlotInfo *slot; PRBool sidOK = PR_TRUE; @@ -2982,6 +3022,12 @@ ssl3_SendClientHello(sslSocket *ss) PK11_FreeSlot(slot); slot = NULL; } + /* do sid-has-FORTEZZA-slot check */ + if (sid->u.ssl3.hasFortezza) { + /* do has fortezza check */ + if (!PK11_VerifyKeyOK(sid->u.ssl3.tek)) + sidOK = PR_FALSE; + } /* If we previously did client-auth, make sure that the token that ** holds the private key still exists, is logged in, hasn't been @@ -3233,6 +3279,35 @@ ssl_UnwrapSymWrappingKey( PORT_Assert(wrappedKey.len <= sizeof pWswk->wrappedSymmetricWrappingkey); switch (exchKeyType) { + PK11SymKey * Ks; + PK11SlotInfo * slot; + SECItem param; + + case kt_fortezza: + /* get the slot that the fortezza server private key is in. */ + slot = PK11_GetSlotFromPrivateKey(svrPrivKey); + if (slot == NULL) { + SET_ERROR_CODE + goto loser; + } + + /* Look up the Token Fixed Key */ + Ks = PK11_FindFixedKey(slot, CKM_SKIPJACK_CBC64, NULL, pwArg); + PK11_FreeSlot(slot); + if (Ks == NULL) { + SET_ERROR_CODE + goto loser; + } + + /* unwrap client write key with the local Ks and IV */ + param.type = siBuffer; + param.data = pWswk->wrapIV; + param.len = pWswk->wrapIVLen; + unwrappedWrappingKey = + PK11_UnwrapSymKey(Ks, CKM_SKIPJACK_CBC64, ¶m, &wrappedKey, + masterWrapMech, CKA_UNWRAP, 0); + PK11_FreeSymKey(Ks); + break; case kt_rsa: unwrappedWrappingKey = @@ -3391,6 +3466,36 @@ getWrappingKey( sslSocket * ss, /* wrap symmetric wrapping key in server's public key. */ switch (exchKeyType) { + PK11SymKey * Ks; + PK11SlotInfo * fSlot; + SECItem param; + + case kt_fortezza: + /* get the slot that the fortezza server private key is in. */ + fSlot = PK11_GetSlotFromPrivateKey(svrPrivKey); + if (fSlot == NULL) { + SET_ERROR_CODE + goto loser; + } + + /* Look up the Token Fixed Key */ + Ks = PK11_FindFixedKey(fSlot, CKM_SKIPJACK_CBC64, NULL, pwArg); + PK11_FreeSlot(fSlot); + if (Ks == NULL) { + SET_ERROR_CODE + goto loser; + } + + /* wrap symmetricWrapping key with the local Ks */ + param.type = siBuffer; + param.data = wswk.wrapIV; + param.len = sizeof wswk.wrapIV; + rv = PK11_WrapSymKey(CKM_SKIPJACK_CBC64, ¶m, Ks, + unwrappedWrappingKey, &wrappedKey); + wswk.wrapIVLen = param.len; + PK11_FreeSymKey(Ks); + asymWrapMechanism = CKM_SKIPJACK_CBC64; + break; case kt_rsa: asymWrapMechanism = CKM_RSA_PKCS; @@ -3449,6 +3554,20 @@ done: } +static SECStatus +ssl3_FortezzaAppendHandshake(sslSocket *ss, unsigned char * data, int len) +{ + SSL3FortezzaKeys *fortezza_CKE = NULL; + SECStatus rv = SECFailure; + + rv = ssl3_AppendHandshakeHeader(ss, client_key_exchange, + (sizeof(*fortezza_CKE)-sizeof(fortezza_CKE->y_c)) + 1 + len); + if (rv == SECSuccess) { + rv = ssl3_AppendHandshakeVariable(ss, data, len, 1); + } + return rv; /* err set by ssl3_AppendHandshake* */ +} + /* Called from ssl3_SendClientKeyExchange(). */ static SECStatus sendRSAClientKeyExchange(sslSocket * ss, SECKEYPublicKey * svrPubKey) @@ -3695,8 +3814,433 @@ loser: } #endif /* NSS_ENABLE_ECC */ +/* fortezza client-auth portion of ClientKeyExchange message + * This function appends the KEA public key from the client's V3 cert + * (empty for a V1 cert) to the outgoing ClientKeyExchange message. + * For a V3 cert, it also computes the Fortezza public key hash of that key + * and signs that hash with the client's signing private key. + * It also finds and returns the client's KEA private key. + * + * Called from sendFortezzaClientKeyExchange <- ssl3_SendClientKeyExchange() + */ +static SECKEYPrivateKey * +sendFortezzaCKXClientAuth(sslSocket *ss, SSL3FortezzaKeys * fortezza_CKE) +{ + SECKEYPublicKey * pubKey = NULL; + SECKEYPrivateKey * privKeaKey = NULL; + CERTCertificate * peerCert = ss->sec.peerCert; + void * pwArg = ss->pkcs11PinArg; + SECStatus rv = SECFailure; + SECItem sigItem; + SECItem hashItem; + + /* extract our own local public key. */ + pubKey = CERT_ExtractPublicKey(ss->ssl3->clientCertificate); + if (!pubKey) { + ssl_MapLowLevelError(SSL_ERROR_EXTRACT_PUBLIC_KEY_FAILURE); + goto loser; + } + + if (pubKey->keyType == fortezzaKey) { + /* fortezza clientauth with fortezza V1 certificate */ + rv = ssl3_FortezzaAppendHandshake(ss, NULL, 0); + if (rv != SECSuccess) { + goto loser; /* err was set by AppendHandshake. */ + } + privKeaKey = PK11_FindKeyByAnyCert(ss->ssl3->clientCertificate, pwArg); + if (!privKeaKey) { + ssl_MapLowLevelError(SEC_ERROR_NO_KEY); + } + + } else { + /* fortezza clientauth w/ V3 certificate or non fortezza cert*/ + CERTCertificate * ccert = NULL; + SECKEYPublicKey * foundPubKey = NULL; + unsigned char hash[SHA1_LENGTH]; + + ccert = PK11_FindBestKEAMatch(peerCert, pwArg); + if (ccert == NULL) { + PORT_SetError(SSL_ERROR_FORTEZZA_PQG); + goto v3_loser; + } + + foundPubKey = CERT_ExtractPublicKey(ccert); + if (foundPubKey == NULL) { + ssl_MapLowLevelError(SSL_ERROR_EXTRACT_PUBLIC_KEY_FAILURE); + goto v3_loser; + } + + if (foundPubKey->keyType == keaKey) { + rv = ssl3_FortezzaAppendHandshake(ss, + foundPubKey->u.kea.publicValue.data, + foundPubKey->u.kea.publicValue.len); + if (rv != SECSuccess) { + goto v3_loser; /* err was set by AppendHandshake. */ + } + + rv = ssl3_ComputeFortezzaPublicKeyHash( + foundPubKey->u.kea.publicValue, hash); + if (rv != SECSuccess) { + ssl_MapLowLevelError(SSL_ERROR_CLIENT_KEY_EXCHANGE_FAILURE); + goto v3_loser; + } + } else { + rv = ssl3_FortezzaAppendHandshake(ss, + foundPubKey->u.fortezza.KEAKey.data, + foundPubKey->u.fortezza.KEAKey.len); + if (rv != SECSuccess) { + goto v3_loser; /* err was set by AppendHandshake. */ + } + + rv = ssl3_ComputeFortezzaPublicKeyHash( + foundPubKey->u.fortezza.KEAKey, hash); + if (rv != SECSuccess) { + ssl_MapLowLevelError(SSL_ERROR_CLIENT_KEY_EXCHANGE_FAILURE); + goto v3_loser; + } + } + + hashItem.data = (unsigned char *) hash; + hashItem.len = SHA1_LENGTH; + + sigItem.data = fortezza_CKE->y_signature; + sigItem.len = sizeof fortezza_CKE->y_signature; + + rv = PK11_Sign(ss->ssl3->clientPrivateKey, &sigItem, &hashItem); + if (rv != SECSuccess) { + ssl_MapLowLevelError(SSL_ERROR_CLIENT_KEY_EXCHANGE_FAILURE); + goto v3_loser; + } + + privKeaKey = PK11_FindKeyByAnyCert(ccert, pwArg); + if (!privKeaKey) { + ssl_MapLowLevelError(SEC_ERROR_NO_KEY); + } + +v3_loser: + if (foundPubKey) + SECKEY_DestroyPublicKey(foundPubKey); + if (ccert) + CERT_DestroyCertificate(ccert); + } /* fortezza clientauth w/ V3 certificate or non fortezza cert*/ + +loser: + + if (pubKey) + SECKEY_DestroyPublicKey(pubKey); + return privKeaKey; +} /* End of fortezza client-auth. */ + + +/* fortezza without client-auth */ +/* fortezza client-auth portion of ClientKeyExchange message + * This function appends the public KEA key from the client's cert + * to the outgoing ClientKeyExchange message. + * It also finds and returns the client's KEA private key. + * + * Called from sendFortezzaClientKeyExchange <- ssl3_SendClientKeyExchange() + */ +static SECKEYPrivateKey * +sendFortezzaCKXNoClientAuth(sslSocket *ss) +{ + SECKEYPublicKey * foundPubKey = NULL; + SECKEYPrivateKey * privKeaKey = NULL; + CERTCertificate * ccert = NULL; + CERTCertificate * peerCert = ss->sec.peerCert; + void * pwArg = ss->pkcs11PinArg; + SECStatus rv = SECFailure; + + ccert = PK11_FindBestKEAMatch(peerCert, pwArg); + if (ccert == NULL) { + PORT_SetError(SSL_ERROR_FORTEZZA_PQG); + goto loser; + } + + foundPubKey = CERT_ExtractPublicKey(ccert); + if (foundPubKey == NULL) { + ssl_MapLowLevelError(SSL_ERROR_EXTRACT_PUBLIC_KEY_FAILURE); + goto loser; + } + + if (foundPubKey->keyType == fortezzaKey) { + /* fortezza V1 cert */ + rv = ssl3_FortezzaAppendHandshake(ss, + foundPubKey->u.fortezza.KEAKey.data, + foundPubKey->u.fortezza.KEAKey.len); + if (rv != SECSuccess) { + goto loser; /* err was set by AppendHandshake. */ + } + privKeaKey = PK11_FindKeyByAnyCert(ccert, pwArg); + if (!privKeaKey) { + ssl_MapLowLevelError(SEC_ERROR_NO_KEY); + } + } else { + /* fortezza V3 cert */ + rv = ssl3_FortezzaAppendHandshake(ss, + foundPubKey->u.kea.publicValue.data, + foundPubKey->u.kea.publicValue.len); + if (rv != SECSuccess) { + goto loser; /* err was set by AppendHandshake. */ + } + privKeaKey = PK11_FindKeyByAnyCert(ccert, pwArg); + if (!privKeaKey) { + ssl_MapLowLevelError(SEC_ERROR_NO_KEY); + } + } + +loser: + if (foundPubKey) + SECKEY_DestroyPublicKey(foundPubKey); + if (ccert) + CERT_DestroyCertificate(ccert); + return privKeaKey; +} + +/* Called from ssl3_SendClientKeyExchange(). */ +static SECStatus +sendFortezzaClientKeyExchange(sslSocket * ss, SECKEYPublicKey * serverKey) +{ + ssl3CipherSpec * pwSpec = NULL; + sslSessionID * sid = ss->sec.ci.sid; + PK11SlotInfo * slot = NULL; + PK11SymKey * pms = NULL; + PK11SymKey * tek = NULL; + PK11SymKey * client_write_key = NULL; + PK11SymKey * server_write_key = NULL; + SECKEYPrivateKey * privKeaKey = NULL; + void * pwArg = ss->pkcs11PinArg; + SECStatus rv = SECFailure; + CK_VERSION version; + SECItem param; + SECItem raItem; + SECItem rbItem; + SECItem enc_pms; + SECItem item; + SSL3FortezzaKeys fortezza_CKE; + PRBool releaseSpecWriteLock = PR_FALSE; + + PORT_Assert( ssl_HaveXmitBufLock(ss)); + PORT_Assert( ssl_HaveSSL3HandshakeLock(ss) ); + + /* first get an appropriate slot for doing MACing. + * Note: This slot will NOT be a Fortezza slot because Fortezza + * cannot generate an SSL3 pre-master-secret. + */ + slot = PK11_GetBestSlot(CKM_SSL3_PRE_MASTER_KEY_GEN, pwArg); + if (slot == NULL) { + PORT_SetError(SSL_ERROR_TOKEN_SLOT_NOT_FOUND); + goto loser; + } + + /* create a pre-Master secret */ + version.major = MSB(ss->version); + version.minor = LSB(ss->version); + + param.data = (unsigned char *)&version; + param.len = sizeof version; + + pms = PK11_KeyGen(slot, CKM_SSL3_PRE_MASTER_KEY_GEN, + ¶m, 0, pwArg); + PK11_FreeSlot(slot); + slot = NULL; + if (pms == NULL) { + ssl_MapLowLevelError(SSL_ERROR_CLIENT_KEY_EXCHANGE_FAILURE); + goto loser; + } + + /* If we don't have a certificate, we need to read out your public key. + * This changes a bit when we need to deal with the PQG stuff + */ + PORT_Memset(fortezza_CKE.y_signature, 0, sizeof fortezza_CKE.y_signature); + + /* Send the KEA public key and get the KEA private key. */ + if (ss->ssl3->clientCertificate != NULL) { + /* with client-auth */ + privKeaKey = sendFortezzaCKXClientAuth(ss, &fortezza_CKE); + } else { + /* without client-auth */ + privKeaKey = sendFortezzaCKXNoClientAuth(ss); + } + if (privKeaKey == NULL) { + rv = SECFailure; + goto loser; /* error was already set. */ + } + + /* Now we derive the TEK, and generate r_c the client's "random" public key. + * r_c is generated and filled in by the PubDerive call below. + */ + raItem.data = fortezza_CKE.r_c; + raItem.len = sizeof fortezza_CKE.r_c; + + /* R_s == server's "random" public key, sent in the Server Key Exchange */ + rbItem.data = ss->ssl3->fortezza.R_s; + rbItem.len = sizeof ss->ssl3->fortezza.R_s; + + tek = PK11_PubDerive(privKeaKey, serverKey, PR_TRUE, /* generate r_c */ + &raItem, &rbItem, CKM_KEA_KEY_DERIVE, + CKM_SKIPJACK_WRAP, CKA_WRAP, 0, pwArg); + SECKEY_DestroyPrivateKey(privKeaKey); + privKeaKey = NULL; + if (tek == NULL) { + ssl_MapLowLevelError(SSL_ERROR_CLIENT_KEY_EXCHANGE_FAILURE); + goto loser; + } + + ss->ssl3->fortezza.tek = PK11_ReferenceSymKey(tek); /* can't fail. */ + + /* encrypt the pms with the TEK. + * NB: PK11_WrapSymKey will generate and output the encrypted PMS + * AND the IV for decrypting the PMS. + */ + param.data = fortezza_CKE.master_secret_iv; + param.len = sizeof fortezza_CKE.master_secret_iv; + + enc_pms.data = fortezza_CKE.encrypted_preMasterSecret; + enc_pms.len = sizeof fortezza_CKE.encrypted_preMasterSecret; + + rv = PK11_WrapSymKey(CKM_SKIPJACK_CBC64, ¶m, tek, pms, &enc_pms); + if (rv != SECSuccess) { + ssl_MapLowLevelError(SSL_ERROR_CLIENT_KEY_EXCHANGE_FAILURE); + goto loser; + } + rv = SECFailure; /* not there yet. */ + + slot = PK11_GetSlotFromKey(tek); + + ssl_GetSpecWriteLock(ss); releaseSpecWriteLock = PR_TRUE; + + pwSpec = ss->ssl3->pwSpec; + pwSpec->client.write_key = client_write_key = + PK11_KeyGen(slot, CKM_SKIPJACK_CBC64, NULL, 0, pwArg); + if (client_write_key == NULL) { + ssl_MapLowLevelError(SSL_ERROR_CLIENT_KEY_EXCHANGE_FAILURE); + goto loser; + } + /* the -1 is a hack. It's supposed to be key size, but we use it + * to tell the wrapper that we're doing a weird PKCS #11 key gen. + * Usually the result of key gen is an encrypt key. This is not + * the case with SSL, where this key is a decrypt key. + */ + pwSpec->server.write_key = server_write_key = + PK11_KeyGen(slot, CKM_SKIPJACK_CBC64, NULL, -1, pwArg); + if (server_write_key == NULL) { + ssl_MapLowLevelError(SSL_ERROR_CLIENT_KEY_EXCHANGE_FAILURE); + goto loser; + } + + rv = ssl3_InitPendingCipherSpec(ss, pms); + PK11_FreeSymKey(pms); pms = NULL; + if (rv != SECSuccess) { + ssl_MapLowLevelError(SSL_ERROR_CLIENT_KEY_EXCHANGE_FAILURE); + goto loser; + } + + /* copy the keys and IVs out now */ + item.data = fortezza_CKE.wrapped_client_write_key; + item.len = sizeof fortezza_CKE.wrapped_client_write_key; + rv = PK11_WrapSymKey(CKM_SKIPJACK_WRAP, NULL, tek, client_write_key, &item); + if (rv != SECSuccess) { + ssl_MapLowLevelError(SSL_ERROR_CLIENT_KEY_EXCHANGE_FAILURE); + goto loser; + } + + item.data = fortezza_CKE.wrapped_server_write_key; + item.len = sizeof fortezza_CKE.wrapped_server_write_key; + rv = PK11_WrapSymKey(CKM_SKIPJACK_WRAP, NULL, tek, server_write_key, &item); + if (rv != SECSuccess) { + ssl_MapLowLevelError(SSL_ERROR_CLIENT_KEY_EXCHANGE_FAILURE); + goto loser; + } + + /* we only get the generated IV's if we're doing skipjack. */ + if (pwSpec->cipher_def->calg == calg_fortezza) { + PORT_Memcpy(fortezza_CKE.client_write_iv, pwSpec->client.write_iv, + sizeof fortezza_CKE.client_write_iv); + PORT_Memcpy(fortezza_CKE.server_write_iv, pwSpec->server.write_iv, + sizeof fortezza_CKE.server_write_iv); + } else { + /* generate IVs to make old servers happy */ + rv = PK11_GenerateFortezzaIV(client_write_key, + fortezza_CKE.client_write_iv, + sizeof fortezza_CKE.client_write_iv); + if (rv != SECSuccess) { + ssl_MapLowLevelError(SSL_ERROR_CLIENT_KEY_EXCHANGE_FAILURE); + goto loser; + } + rv = PK11_GenerateFortezzaIV(server_write_key, + fortezza_CKE.server_write_iv, + sizeof fortezza_CKE.server_write_iv); + if (rv != SECSuccess) { + ssl_MapLowLevelError(SSL_ERROR_CLIENT_KEY_EXCHANGE_FAILURE); + goto loser; + } + } + /* NOTE: This technique of writing out the struct, rather than writing + * out the individual members works only because all the rest of the + * values are fixed-length strings of well-defined byte order. + * Add one SECItem or one Number and we will need to break the elements out. + */ + rv = ssl3_AppendHandshake(ss, &fortezza_CKE.r_c, + (sizeof fortezza_CKE - sizeof fortezza_CKE.y_c)); + if (rv != SECSuccess) { + goto loser; /* err was set by AppendHandshake. */ + } + + /* now we initialize our contexts */ + sid->u.ssl3.hasFortezza = PR_TRUE; + sid->u.ssl3.tek = tek; tek = NULL; /* adopt.. */ + + if (pwSpec->cipher_def->calg == calg_fortezza) { + sid->u.ssl3.clientWriteKey = + PK11_ReferenceSymKey(pwSpec->client.write_key); + sid->u.ssl3.serverWriteKey= + PK11_ReferenceSymKey(pwSpec->server.write_key); + + PORT_Memcpy(sid->u.ssl3.keys.client_write_iv, + pwSpec->client.write_iv, + sizeof sid->u.ssl3.keys.client_write_iv); + PORT_Memcpy(sid->u.ssl3.keys.server_write_iv, + pwSpec->server.write_iv, + sizeof sid->u.ssl3.keys.server_write_iv); + + rv = PK11_SaveContext((PK11Context *)pwSpec->encodeContext, + sid->u.ssl3.clientWriteSave, + &sid->u.ssl3.clientWriteSaveLen, + sizeof sid->u.ssl3.clientWriteSave); + if (rv != SECSuccess) { + ssl_MapLowLevelError(SSL_ERROR_CLIENT_KEY_EXCHANGE_FAILURE); + goto loser; + } + } else { + PK11_FreeSymKey(client_write_key); + pwSpec->client.write_key = client_write_key = NULL; + + PK11_FreeSymKey(server_write_key); + pwSpec->server.write_key = server_write_key = NULL; + + rv = SECSuccess; + } + /* FALL THROUGH */ +loser: + if (tek) PK11_FreeSymKey(tek); + if (slot) PK11_FreeSlot(slot); + if (pms) PK11_FreeSymKey(pms); + if (rv != SECSuccess) { + if (client_write_key) { + PK11_FreeSymKey(client_write_key); + pwSpec->client.write_key = client_write_key = NULL; + } + if (server_write_key) { + PK11_FreeSymKey(server_write_key); + pwSpec->server.write_key = server_write_key = NULL; + } + } + if (releaseSpecWriteLock) + ssl_GetSpecWriteLock(ss); + return rv; +} /* Called from ssl3_HandleServerHelloDone(). */ static SECStatus @@ -3746,6 +4290,10 @@ ssl3_SendClientKeyExchange(sslSocket *ss) rv = sendRSAClientKeyExchange(ss, serverKey); break; + case kt_fortezza: + rv = sendFortezzaClientKeyExchange(ss, serverKey); + break; + case kt_dh: rv = sendDHClientKeyExchange(ss, serverKey); break; @@ -3813,7 +4361,7 @@ ssl3_SendCertificateVerify(sslSocket *ss) PK11_FreeSlot(slot); } /* If we're doing RSA key exchange, we're all done with the private key - * here. Diffie-Hellman key exchanges need the client's + * here. Diffie-Hellman & Fortezza key exchanges need the client's * private key for the key exchange. */ if (ssl3->hs.kea_def->exchKeyType == kt_rsa) { @@ -4038,11 +4586,39 @@ ssl3_HandleServerHello(sslSocket *ss, SSL3Opaque *b, PRUint32 length) ss->sec.peerCert = CERT_DupCertificate(sid->peerCert); } + /* reload the FORTEZZA key material. These keys aren't generated + * by the master secret, but by the key exchange. We restart by + * reusing these keys. */ + if (sid->u.ssl3.hasFortezza) { + ss->ssl3->fortezza.tek = PK11_ReferenceSymKey(sid->u.ssl3.tek); + } + if (ss->ssl3->hs.suite_def->bulk_cipher_alg == cipher_fortezza) { + ss->ssl3->pwSpec->client.write_key = + PK11_ReferenceSymKey(sid->u.ssl3.clientWriteKey); + ss->ssl3->pwSpec->server.write_key = + PK11_ReferenceSymKey(sid->u.ssl3.serverWriteKey); + /* add the tek later for pre-encrypted files */ + PORT_Memcpy(ss->ssl3->pwSpec->client.write_iv, + sid->u.ssl3.keys.client_write_iv, + sizeof sid->u.ssl3.keys.client_write_iv); + PORT_Memcpy(ss->ssl3->pwSpec->server.write_iv, + sid->u.ssl3.keys.server_write_iv, + sizeof sid->u.ssl3.keys.server_write_iv); + } /* NULL value for PMS signifies re-use of the old MS */ rv = ssl3_InitPendingCipherSpec(ss, NULL); if (rv != SECSuccess) { - goto alert_loser; /* err code was set */ + goto alert_loser; /* err code was set by ssl3_InitPendingCipherSpec */ + } + if (ss->ssl3->hs.suite_def->bulk_cipher_alg == cipher_fortezza) { + rv = PK11_RestoreContext( + (PK11Context *)ss->ssl3->pwSpec->encodeContext, + sid->u.ssl3.clientWriteSave, + sid->u.ssl3.clientWriteSaveLen); + if (rv != SECSuccess) { + goto alert_loser; /* err is set. */ + } } SECITEM_ZfreeItem(&sidBytes, PR_FALSE); return SECSuccess; @@ -4398,6 +4974,26 @@ ssl3_HandleServerKeyExchange(sslSocket *ss, SSL3Opaque *b, PRUint32 length) return SECSuccess; #endif /* NSS_ENABLE_ECC */ + case kt_fortezza: + + /* Fortezza needs *BOTH* a server cert message + * and a server key exchange message. + */ + if (ss->ssl3->hs.ws == wait_server_cert) { + errCode = SSL_ERROR_RX_UNEXPECTED_SERVER_KEY_EXCH; + desc = unexpected_message; + goto alert_loser; + } + /* Get the server's "random" public key. */ + rv = ssl3_ConsumeHandshake(ss, ss->ssl3->fortezza.R_s, + sizeof ss->ssl3->fortezza.R_s, &b, &length); + if (rv != SECSuccess) { + goto loser; /* malformed */ + } + + ss->ssl3->hs.ws = wait_cert_request; + return SECSuccess; + default: desc = handshake_failure; errCode = SEC_ERROR_UNSUPPORTED_KEYALG; @@ -4811,6 +5407,7 @@ ssl3_NewSessionID(sslSocket *ss, PRBool is_server) sid->u.ssl3.resumable = PR_TRUE; sid->u.ssl3.policy = SSL_ALLOWED; + sid->u.ssl3.hasFortezza = PR_FALSE; sid->u.ssl3.clientWriteKey = NULL; sid->u.ssl3.serverWriteKey = NULL; sid->u.ssl3.tek = NULL; @@ -4859,8 +5456,12 @@ ssl3_SendServerHelloSequence(sslSocket *ss) */ kea_def = ss->ssl3->hs.kea_def; ss->ssl3->hs.usedStepDownKey = PR_FALSE; - - if (kea_def->is_limited && kea_def->exchKeyType == kt_rsa) { + if (kea_def->kea == kea_fortezza) { + rv = ssl3_SendServerKeyExchange(ss); + if (rv != SECSuccess) { + return rv; /* err code was set. */ + } + } else if (kea_def->is_limited && kea_def->exchKeyType == kt_rsa) { /* see if we can legally use the key in the cert. */ int keyLen; /* bytes */ @@ -5116,6 +5717,7 @@ compression_found: * as if the client had sent us no sid to begin with, and make a new one. */ if (sid != NULL) do { + PK11SlotInfo * slot; PK11SymKey * wrapKey; /* wrapping key */ SECItem wrappedKey; /* wrapped key */ ssl3CipherSpec *pwSpec; @@ -5196,6 +5798,74 @@ compression_found: goto loser; } + /* reload the FORTEZZA key material. + * On Fortezza, the following keys & IVs are generated by the KEA, + * not from the PMS. Since we're not going to redo the KEA, we + * have to save & restore them for Fortezza. + * use kea because we haven't call InitCipher Specs yet...? + */ + if (ssl3->hs.suite_def->bulk_cipher_alg == cipher_fortezza) { + PK11SymKey * Ks; + SECItem item; + + PORT_Memcpy(pwSpec->client.write_iv, + sid->u.ssl3.keys.client_write_iv, + sizeof sid->u.ssl3.keys.client_write_iv); + PORT_Memcpy(pwSpec->server.write_iv, + sid->u.ssl3.keys.server_write_iv, + sizeof sid->u.ssl3.keys.server_write_iv); + + /* Now, unwrap the client and server write keys with Ks */ + + /* get the slot that the fortezza server private key is in. */ + slot = PK11_GetSlotFromPrivateKey( + ss->serverCerts[kt_fortezza].serverKey); + if (slot == NULL) { + ssl_MapLowLevelError(SSL_ERROR_CLIENT_KEY_EXCHANGE_FAILURE); + goto loser; + } + + /* Look up the Token Fixed Key */ + Ks = PK11_FindFixedKey(slot, CKM_SKIPJACK_WRAP, NULL, + ss->pkcs11PinArg); + PK11_FreeSlot(slot); + if (Ks == NULL) { + ssl_MapLowLevelError(SSL_ERROR_CLIENT_KEY_EXCHANGE_FAILURE); + goto loser; + } + + /* unwrap client write key with the local Ks */ + item.data = sid->u.ssl3.keys.wrapped_client_write_key; + item.len = sizeof sid->u.ssl3.keys.wrapped_client_write_key; + + pwSpec->client.write_key = + PK11_UnwrapSymKey(Ks, CKM_SKIPJACK_WRAP, NULL, &item, + CKM_SKIPJACK_CBC64, CKA_DECRYPT, 0); + if (pwSpec->client.write_key == NULL) { + SEND_ALERT + ssl_MapLowLevelError(SSL_ERROR_SYM_KEY_UNWRAP_FAILURE); + goto loser; + } + + /* unwrap server write key with the local Ks */ + item.data = sid->u.ssl3.keys.wrapped_server_write_key; + item.len = sizeof sid->u.ssl3.keys.wrapped_server_write_key; + + pwSpec->server.write_key = + PK11_UnwrapSymKey(Ks, CKM_SKIPJACK_WRAP, NULL, &item, + CKM_SKIPJACK_CBC64, CKA_ENCRYPT, 0); + if (pwSpec->server.write_key == NULL) { + PK11_FreeSymKey(pwSpec->client.write_key); + pwSpec->client.write_key = NULL; + SEND_ALERT + ssl_MapLowLevelError(SSL_ERROR_SYM_KEY_UNWRAP_FAILURE); + goto loser; + } + /* Set flag that says "generate 8 byte random prefix plaintext." */ + PK11_SetFortezzaHack(pwSpec->server.write_key); /* can't fail */ + + } + if (haveSpecWriteLock) { ssl_ReleaseSpecWriteLock(ss); haveSpecWriteLock = PR_FALSE; @@ -5606,6 +6276,27 @@ const ssl3KEADef * kea_def = ss->ssl3->hs.kea_def; PORT_Free(signed_hash.data); return SECSuccess; + case kt_fortezza: + + /* Set server's "random" public key R_s to the email value == 1 */ + PORT_Memset(ss->ssl3->fortezza.R_s, 0, sizeof(ss->ssl3->fortezza.R_s)); + ss->ssl3->fortezza.R_s[127] = 1; + + /* don't waste time signing the random number */ + length = sizeof (ss->ssl3->fortezza.R_s) /*+ 2 + signed_hash.len*/; + + rv = ssl3_AppendHandshakeHeader(ss, server_key_exchange, length); + if (rv != SECSuccess) { + goto loser; /* err set by AppendHandshake. */ + } + + rv = ssl3_AppendHandshake( ss, &ss->ssl3->fortezza.R_s, + sizeof(ss->ssl3->fortezza.R_s)); + if (rv != SECSuccess) { + goto loser; /* err set by AppendHandshake. */ + } + return SECSuccess; + #ifdef NSS_ENABLE_ECC case kt_ecdh: /* Generate ephemeral ECDH key pair and send the public key */ @@ -5750,8 +6441,13 @@ const uint8 * certTypes; calen += 2 + name->len; } - certTypes = certificate_types; - certTypesLength = sizeof certificate_types; + if (ss->ssl3->hs.kea_def->exchKeyType == kt_fortezza) { + certTypes = fortezza_certificate_types; + certTypesLength = sizeof fortezza_certificate_types; + } else { + certTypes = certificate_types; + certTypesLength = sizeof certificate_types; + } length = 1 + certTypesLength + 2 + calen; @@ -5858,6 +6554,256 @@ loser: return SECFailure; } +/* +** Called from ssl3_HandleClientKeyExchange() +*/ +static SECStatus +ssl3_HandleFortezzaClientKeyExchange(sslSocket *ss, SSL3Opaque *b, + PRUint32 length, + SECKEYPrivateKey *serverKey) +{ + SECKEYPublicKey * pubKey = NULL; + PK11SymKey * tek = NULL; + PK11SymKey * pms; + PK11SymKey * Ks = NULL; + sslSessionID * sid = ss->sec.ci.sid; + ssl3CipherSpec * pwSpec = ss->ssl3->pwSpec; + void * pwArg = ss->pkcs11PinArg; + SECStatus rv; + SECItem raItem; + SECItem rbItem; + SECItem param; + SECItem item; + SECItem enc_pms; + SSL3FortezzaKeys fortezza_CKE; + + PORT_Assert( ssl_HaveRecvBufLock(ss) ); + PORT_Assert( ssl_HaveSSL3HandshakeLock(ss) ); + + fortezza_CKE.y_c.data = NULL; + rv = ssl3_ConsumeHandshakeVariable(ss, &fortezza_CKE.y_c, 1, &b, &length); + if (rv != SECSuccess) { + PORT_SetError(SSL_ERROR_RX_MALFORMED_CLIENT_KEY_EXCH); + goto fortezza_loser; + } + rv = ssl3_ConsumeHandshake(ss, &fortezza_CKE.r_c, + sizeof fortezza_CKE - sizeof fortezza_CKE.y_c, + &b, &length); + if (rv != SECSuccess) { + PORT_SetError(SSL_ERROR_RX_MALFORMED_CLIENT_KEY_EXCH); + goto fortezza_loser; + } + + /* Build a Token Encryption key (tek). TEK's can never be unloaded + * from the card, but given these parameters, and *OUR* fortezza + * card, we can always regenerate the same one on the fly. + */ + if (ss->sec.peerCert != NULL) { + /* client-auth case */ + + pubKey = CERT_ExtractPublicKey(ss->sec.peerCert); + if (pubKey == NULL) { + SEND_ALERT + PORT_SetError(SSL_ERROR_EXTRACT_PUBLIC_KEY_FAILURE); + rv = SECFailure; + goto fortezza_loser; + } + + if (pubKey->keyType != fortezzaKey) { + /* handle V3 client-auth case */ + SECItem sigItem; + SECItem hashItem; + unsigned char hash[SHA1_LENGTH]; + + rv = ssl3_ComputeFortezzaPublicKeyHash(fortezza_CKE.y_c, hash); + if (rv != SECSuccess) { + SEND_ALERT + ssl_MapLowLevelError(SSL_ERROR_CLIENT_KEY_EXCHANGE_FAILURE); + goto fortezza_loser; + } + sigItem.data = fortezza_CKE.y_signature; + sigItem.len = sizeof fortezza_CKE.y_signature; + + hashItem.data = hash; + hashItem.len = sizeof hash; + + rv = PK11_Verify(pubKey, &sigItem, &hashItem, pwArg); + if (rv != SECSuccess) { + SSL3_SendAlert(ss, alert_fatal, illegal_parameter); + ssl_MapLowLevelError(SSL_ERROR_CLIENT_KEY_EXCHANGE_FAILURE); + goto fortezza_loser; + } + SECKEY_DestroyPublicKey(pubKey); pubKey = NULL; + } + } + rv = SECFailure; + + /* Make the public key if necessary */ + if (fortezza_CKE.y_c.len != 0) { + if (pubKey != NULL) { + /* The client is not allowed to send the public key + * if it can be extracted from the certificate. */ + SSL3_SendAlert(ss, alert_fatal, illegal_parameter); + PORT_SetError(SSL_ERROR_CLIENT_KEY_EXCHANGE_FAILURE); + goto fortezza_loser; + } + pubKey = PK11_MakeKEAPubKey(fortezza_CKE.y_c.data, + fortezza_CKE.y_c.len); + } + if (pubKey == NULL) { + /* no public Key in either the cert or the protocol message*/ + SSL3_SendAlert(ss, alert_fatal, illegal_parameter); + PORT_SetError(SSL_ERROR_CLIENT_KEY_EXCHANGE_FAILURE); + goto fortezza_loser; + } + + /* Now we derive the TEK. r_c is the client's "random" public key. */ + raItem.data = fortezza_CKE.r_c; + raItem.len = sizeof(fortezza_CKE.r_c); + + /* R_s == server's "random" public key, sent in the Server Key Exchange */ + rbItem.data = ss->ssl3->fortezza.R_s; + rbItem.len = sizeof ss->ssl3->fortezza.R_s; + + tek = PK11_PubDerive(serverKey, pubKey, PR_FALSE, /* don't gen r_c */ + &raItem, &rbItem, CKM_KEA_KEY_DERIVE, + CKM_SKIPJACK_WRAP, CKA_WRAP, 0, pwArg); + SECKEY_DestroyPublicKey(pubKey); pubKey = NULL; + if (tek == NULL) { + SEND_ALERT + ssl_MapLowLevelError(SSL_ERROR_CLIENT_KEY_EXCHANGE_FAILURE); + goto fortezza_loser; + } + + ss->ssl3->fortezza.tek = PK11_ReferenceSymKey(tek); + + if (pwSpec->cipher_def->calg == calg_fortezza) { + item.data = fortezza_CKE.wrapped_client_write_key; + item.len = sizeof fortezza_CKE.wrapped_client_write_key; + + pwSpec->client.write_key = + PK11_UnwrapSymKey(tek, CKM_SKIPJACK_WRAP, NULL, &item, + CKM_SKIPJACK_CBC64, CKA_DECRYPT, 0); + if (pwSpec->client.write_key == NULL) { + SEND_ALERT + ssl_MapLowLevelError(SSL_ERROR_SYM_KEY_UNWRAP_FAILURE); + goto fortezza_loser; + } + + item.data = fortezza_CKE.wrapped_server_write_key; + item.len = sizeof fortezza_CKE.wrapped_server_write_key; + + pwSpec->server.write_key = + PK11_UnwrapSymKey(tek, CKM_SKIPJACK_WRAP, NULL, &item, + CKM_SKIPJACK_CBC64, CKA_ENCRYPT, 0); + if (pwSpec->server.write_key == NULL) { + PK11_FreeSymKey(pwSpec->client.write_key); + pwSpec->client.write_key = NULL; + SEND_ALERT + ssl_MapLowLevelError(SSL_ERROR_SYM_KEY_UNWRAP_FAILURE); + goto fortezza_loser; + } + /* Set a flag that says "generate 8 byte random prefix plaintext." */ + PK11_SetFortezzaHack(pwSpec->server.write_key); /* can't fail */ + + PORT_Memcpy(pwSpec->client.write_iv, fortezza_CKE.client_write_iv, + sizeof fortezza_CKE.client_write_iv); + PORT_Memcpy(pwSpec->server.write_iv, fortezza_CKE.server_write_iv, + sizeof fortezza_CKE.server_write_iv); + + } + + /* decrypt the pms with the TEK */ + enc_pms.data = fortezza_CKE.encrypted_preMasterSecret; + enc_pms.len = sizeof fortezza_CKE.encrypted_preMasterSecret; + + param.data = fortezza_CKE.master_secret_iv; + param.len = sizeof fortezza_CKE.master_secret_iv; + + pms = PK11_UnwrapSymKey(tek, CKM_SKIPJACK_CBC64, ¶m, &enc_pms, + CKM_SSL3_MASTER_KEY_DERIVE, CKA_DERIVE, 0); + if (pms == NULL) { + SEND_ALERT + ssl_MapLowLevelError(SSL_ERROR_SYM_KEY_UNWRAP_FAILURE); + goto fortezza_loser; + } + + rv = ssl3_InitPendingCipherSpec(ss, pms); + PK11_FreeSymKey(pms); + if (rv != SECSuccess) { + SEND_ALERT + goto fortezza_loser; /* err code is set. */ + } + + if (pwSpec->cipher_def->calg == calg_fortezza) { + PK11SlotInfo * slot; + + sid->u.ssl3.clientWriteKey = + PK11_ReferenceSymKey(pwSpec->client.write_key); + sid->u.ssl3.serverWriteKey = + PK11_ReferenceSymKey(pwSpec->server.write_key); + + PORT_Memcpy(sid->u.ssl3.keys.client_write_iv, pwSpec->client.write_iv, + sizeof sid->u.ssl3.keys.client_write_iv); + PORT_Memcpy(sid->u.ssl3.keys.server_write_iv, pwSpec->server.write_iv, + sizeof sid->u.ssl3.keys.server_write_iv); + + /* Now, wrap the client and server write keys in Ks for storage + * in the on-disk sid. + */ + + slot = PK11_GetSlotFromKey(tek); /* get ref to the slot */ + if (slot == NULL) { + ssl_MapLowLevelError(SSL_ERROR_CLIENT_KEY_EXCHANGE_FAILURE); + goto fortezza_loser; + } + + /* Look up the Token Fixed Key */ + Ks = PK11_FindFixedKey(slot, CKM_SKIPJACK_WRAP, NULL, ss->pkcs11PinArg); + PK11_FreeSlot(slot); + if (Ks == NULL) { + ssl_MapLowLevelError(SSL_ERROR_CLIENT_KEY_EXCHANGE_FAILURE); + goto fortezza_loser; + } + + /* rewrap server write key with the local Ks */ + item.data = sid->u.ssl3.keys.wrapped_server_write_key; + item.len = sizeof sid->u.ssl3.keys.wrapped_server_write_key; + rv = PK11_WrapSymKey(CKM_SKIPJACK_WRAP, NULL, Ks, + pwSpec->server.write_key, &item); + if (rv != SECSuccess) { + ssl_MapLowLevelError(SSL_ERROR_CLIENT_KEY_EXCHANGE_FAILURE); + goto fortezza_loser; + } + + /* rewrap client write key with the local Ks */ + item.data = sid->u.ssl3.keys.wrapped_client_write_key; + item.len = sizeof sid->u.ssl3.keys.wrapped_client_write_key; + rv = PK11_WrapSymKey(CKM_SKIPJACK_WRAP, NULL, Ks, + pwSpec->client.write_key, &item); + if (rv != SECSuccess) { + ssl_MapLowLevelError(SSL_ERROR_CLIENT_KEY_EXCHANGE_FAILURE); + goto fortezza_loser; + } + + /* wrap the master secret later, when we handle the client's + * finished message. + */ + } + + sid->u.ssl3.hasFortezza = PR_TRUE; + sid->u.ssl3.tek = tek; tek = NULL; + + rv = SECSuccess; + +fortezza_loser: + if (Ks) PK11_FreeSymKey(Ks); + if (tek) PK11_FreeSymKey(tek); + if (pubKey) SECKEY_DestroyPublicKey(pubKey); + if (fortezza_CKE.y_c.data != NULL) + SECITEM_FreeItem(&fortezza_CKE.y_c, PR_FALSE); + return rv; +} /* find a slot that is able to generate a PMS and wrap it with RSA. * Then generate and return the PMS. @@ -6163,6 +7109,12 @@ const ssl3KEADef * kea_def; } break; + case kt_fortezza: + rv = ssl3_HandleFortezzaClientKeyExchange(ss, b, length, serverKey); + if (rv != SECSuccess) { + return SECFailure; /* error code set */ + } + break; #ifdef NSS_ENABLE_ECC case kt_ecdh: @@ -6541,8 +7493,18 @@ ssl3_HandleCertificate(sslSocket *ss, SSL3Opaque *b, PRUint32 length) SECKEY_UpdateCertPQG(ss->sec.peerCert); /* - * Ask caller-supplied callback function to validate cert chain. + * We're making a fortezza connection, and the card hasn't unloaded it's + * certs, try to unload those certs now. */ + if (!trusted) { + CERTCertificate *ccert; + + ccert = PK11_FindBestKEAMatch(ss->sec.peerCert, ss->pkcs11PinArg); + if (ccert) + CERT_DestroyCertificate(ccert); + } + + rv = (SECStatus)(*ss->authCertificate)(ss->authCertificateArg, ss->fd, PR_TRUE, isServer); if (rv) { @@ -6635,6 +7597,7 @@ cert_block: ssl3->hs.ws = wait_cert_request; /* disallow server_key_exchange */ if (ssl3->hs.kea_def->is_limited || /* XXX OR server cert is signing only. */ + ssl3->hs.kea_def->kea == kea_fortezza || #ifdef NSS_ENABLE_ECC ssl3->hs.kea_def->kea == kea_ecdhe_ecdsa || ssl3->hs.kea_def->kea == kea_ecdhe_rsa || @@ -7662,6 +8625,7 @@ ssl3_InitState(sslSocket *ss) ssl3->hs.rehandshake = PR_FALSE; ssl3_InitCipherSpec(ss, ssl3->crSpec); ssl3_InitCipherSpec(ss, ssl3->prSpec); + ssl3->fortezza.tek = NULL; ssl3->hs.ws = (ss->sec.isServer) ? wait_client_hello : wait_server_hello; ssl_ReleaseSpecWriteLock(ss); @@ -8030,6 +8994,9 @@ ssl3_DestroySSL3Info(ssl3State *ssl3) PK11_DestroyContext(ssl3->hs.sha,PR_TRUE); } + if (ssl3->fortezza.tek != NULL) { + PK11_FreeSymKey(ssl3->fortezza.tek); + } /* free the SSL3Buffer (msg_body) */ PORT_Free(ssl3->hs.msg_body.buf); diff --git a/security/nss/lib/ssl/ssl3prot.h b/security/nss/lib/ssl/ssl3prot.h index da1e0d180..c68fa8270 100644 --- a/security/nss/lib/ssl/ssl3prot.h +++ b/security/nss/lib/ssl/ssl3prot.h @@ -1,4 +1,4 @@ -/* Private header file of libSSL. +/* * Various and sundry protocol constants. DON'T CHANGE THESE. These * values are defined by the SSL 3.0 protocol specification. * @@ -206,6 +206,7 @@ typedef enum { kea_dhe_rsa_export, kea_dh_anon, kea_dh_anon_export, + kea_fortezza, kea_rsa_fips, kea_ecdh_ecdsa, kea_ecdhe_ecdsa, @@ -258,6 +259,7 @@ typedef enum { ct_RSA_fixed_ECDH = 8, ct_ECDSA_fixed_ECDH = 9, + ct_Fortezza = 20 } SSL3ClientCertificateType; typedef SECItem *SSL3DistinquishedName; @@ -269,6 +271,18 @@ typedef struct { typedef SECItem SSL3EncryptedPreMasterSecret; +/* Following struct is the format of a Fortezza ClientKeyExchange message. */ +typedef struct { + SECItem y_c; + SSL3Opaque r_c [128]; + SSL3Opaque y_signature [40]; + SSL3Opaque wrapped_client_write_key [12]; + SSL3Opaque wrapped_server_write_key [12]; + SSL3Opaque client_write_iv [24]; + SSL3Opaque server_write_iv [24]; + SSL3Opaque master_secret_iv [24]; + SSL3Opaque encrypted_preMasterSecret[48]; +} SSL3FortezzaKeys; typedef SSL3Opaque SSL3MasterSecret[48]; @@ -285,6 +299,7 @@ typedef struct { union { SSL3EncryptedPreMasterSecret rsa; SSL3ClientDiffieHellmanPublic diffie_helman; + SSL3FortezzaKeys fortezza; } exchange_keys; } SSL3ClientKeyExchange; diff --git a/security/nss/lib/ssl/sslauth.c b/security/nss/lib/ssl/sslauth.c index 24d250018..690008e42 100644 --- a/security/nss/lib/ssl/sslauth.c +++ b/security/nss/lib/ssl/sslauth.c @@ -117,7 +117,8 @@ SSL_SecurityStatus(PRFileDesc *fd, int *op, char **cp, int *kp0, int *kp1, cipherName = ssl3_cipherName[ss->sec.cipherType]; } if (cipherName && PORT_Strstr(cipherName, "DES")) isDes = PR_TRUE; - + /* do same key stuff for fortezza */ + if (cp) { *cp = PORT_Strdup(cipherName); } diff --git a/security/nss/lib/ssl/sslcon.c b/security/nss/lib/ssl/sslcon.c index 278478fc6..da20986b5 100644 --- a/security/nss/lib/ssl/sslcon.c +++ b/security/nss/lib/ssl/sslcon.c @@ -145,7 +145,7 @@ const char * const ssl_cipherName[] = { "DES-CBC", "DES-EDE3-CBC", "unknown", - "unknown", /* was fortezza, NO LONGER USED */ + "Fortezza", }; diff --git a/security/nss/lib/ssl/sslenum.c b/security/nss/lib/ssl/sslenum.c index d28d689b7..2745155af 100644 --- a/security/nss/lib/ssl/sslenum.c +++ b/security/nss/lib/ssl/sslenum.c @@ -56,6 +56,7 @@ const PRUint16 SSL_ImplementedCiphers[] = { TLS_RSA_WITH_AES_256_CBC_SHA, /* 128-bit */ + SSL_FORTEZZA_DMS_WITH_RC4_128_SHA, #ifdef NSS_ENABLE_ECC TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA, TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA, @@ -83,6 +84,9 @@ const PRUint16 SSL_ImplementedCiphers[] = { SSL_RSA_FIPS_WITH_3DES_EDE_CBC_SHA, SSL_RSA_WITH_3DES_EDE_CBC_SHA, + /* 80 bit skipjack */ + SSL_FORTEZZA_DMS_WITH_FORTEZZA_CBC_SHA, /* KEA + SkipJack */ + /* 56-bit DES "domestic" cipher suites */ SSL_DHE_RSA_WITH_DES_CBC_SHA, SSL_DHE_DSS_WITH_DES_CBC_SHA, @@ -102,6 +106,7 @@ const PRUint16 SSL_ImplementedCiphers[] = { SSL_RSA_EXPORT_WITH_RC2_CBC_40_MD5, /* ciphersuites with no encryption */ + SSL_FORTEZZA_DMS_WITH_NULL_SHA, #ifdef NSS_ENABLE_ECC TLS_ECDH_RSA_WITH_NULL_SHA, TLS_ECDH_ECDSA_WITH_NULL_SHA, diff --git a/security/nss/lib/ssl/sslimpl.h b/security/nss/lib/ssl/sslimpl.h index ae6cb8a72..f42bd4be3 100644 --- a/security/nss/lib/ssl/sslimpl.h +++ b/security/nss/lib/ssl/sslimpl.h @@ -84,7 +84,7 @@ typedef SSLSignType SSL3SignType; #define calg_des ssl_calg_des #define calg_3des ssl_calg_3des #define calg_idea ssl_calg_idea -#define calg_fortezza ssl_calg_fortezza /* deprecated, must preserve */ +#define calg_fortezza ssl_calg_fortezza #define calg_aes ssl_calg_aes #define mac_null ssl_mac_null @@ -414,6 +414,7 @@ typedef enum { cipher_3des, cipher_des40, cipher_idea, + cipher_fortezza, cipher_aes_128, cipher_aes_256, cipher_missing /* reserved for no such supported cipher */ @@ -521,6 +522,7 @@ struct sslSessionIDStr { SSL3CompressionMethod compression; PRBool resumable; int policy; + PRBool hasFortezza; ssl3SidKeys keys; CK_MECHANISM_TYPE masterWrapMech; /* mechanism used to wrap master secret */ @@ -558,6 +560,11 @@ struct sslSessionIDStr { char masterValid; char clAuthValid; + /* the following values are used only in the client, and only + * with fortezza. + */ + SSL3Opaque clientWriteSave[80]; + int clientWriteSaveLen; } ssl3; } u; }; @@ -653,7 +660,12 @@ const ssl3CipherSuiteDef *suite_def; /* protected by recvBufLock */ } SSL3HandshakeState; +struct SSL3FortezzaKEAParamsStr { + unsigned char R_s[128]; /* server's "random" public key */ + PK11SymKey * tek; +}; +typedef struct SSL3FortezzaKEAParamsStr SSL3FortezzaKEAParams; /* ** This is the "ssl3" struct, as in "ss->ssl3". @@ -692,7 +704,7 @@ struct ssl3StateStr { /* chain while we are trying to validate it. */ CERTDistNames * ca_list; /* used by server. trusted CAs for this socket. */ - + SSL3FortezzaKEAParams fortezza; }; typedef struct { diff --git a/security/nss/lib/ssl/sslinfo.c b/security/nss/lib/ssl/sslinfo.c index 40dd9b31f..218973a2a 100644 --- a/security/nss/lib/ssl/sslinfo.c +++ b/security/nss/lib/ssl/sslinfo.c @@ -100,6 +100,8 @@ SSL_GetChannelInfo(PRFileDesc *fd, SSLChannelInfo *info, PRUintn len) return SECSuccess; } +#define kt_kea kt_fortezza +#define calg_sj calg_fortezza #define CS(x) x, #x #define CK(x) x | 0xff00, #x @@ -141,6 +143,7 @@ static const SSLCipherSuiteInfo suiteInfo[] = { {0,CS(TLS_DHE_DSS_WITH_AES_256_CBC_SHA), S_DSA, K_DHE, C_AES, B_256, M_SHA, 0, 0, 0, }, {0,CS(TLS_RSA_WITH_AES_256_CBC_SHA), S_RSA, K_RSA, C_AES, B_256, M_SHA, 0, 0, 0, }, +{0,CS(SSL_FORTEZZA_DMS_WITH_RC4_128_SHA), S_KEA, K_KEA, C_RC4, B_128, M_SHA, 0, 0, 0, }, {0,CS(TLS_DHE_DSS_WITH_RC4_128_SHA), S_DSA, K_DHE, C_RC4, B_128, M_SHA, 0, 0, 0, }, {0,CS(TLS_DHE_RSA_WITH_AES_128_CBC_SHA), S_RSA, K_DHE, C_AES, B_128, M_SHA, 0, 0, 0, }, {0,CS(TLS_DHE_DSS_WITH_AES_128_CBC_SHA), S_DSA, K_DHE, C_AES, B_128, M_SHA, 0, 0, 0, }, @@ -153,6 +156,7 @@ static const SSLCipherSuiteInfo suiteInfo[] = { {0,CS(SSL_RSA_FIPS_WITH_3DES_EDE_CBC_SHA), S_RSA, K_RSA, C_3DES,B_3DES,M_SHA, 1, 0, 1, }, {0,CS(SSL_RSA_WITH_3DES_EDE_CBC_SHA), S_RSA, K_RSA, C_3DES,B_3DES,M_SHA, 1, 0, 0, }, +{0,CS(SSL_FORTEZZA_DMS_WITH_FORTEZZA_CBC_SHA),S_KEA, K_KEA, C_SJ, B_SJ, M_SHA, 1, 0, 0, }, {0,CS(SSL_DHE_RSA_WITH_DES_CBC_SHA), S_RSA, K_DHE, C_DES, B_DES, M_SHA, 0, 0, 0, }, {0,CS(SSL_DHE_DSS_WITH_DES_CBC_SHA), S_DSA, K_DHE, C_DES, B_DES, M_SHA, 0, 0, 0, }, {0,CS(SSL_RSA_FIPS_WITH_DES_CBC_SHA), S_RSA, K_RSA, C_DES, B_DES, M_SHA, 1, 0, 1, }, @@ -162,6 +166,7 @@ static const SSLCipherSuiteInfo suiteInfo[] = { {0,CS(TLS_RSA_EXPORT1024_WITH_DES_CBC_SHA), S_RSA, K_RSA, C_DES, B_DES, M_SHA, 1, 1, 0, }, {0,CS(SSL_RSA_EXPORT_WITH_RC4_40_MD5), S_RSA, K_RSA, C_RC4, B_40, M_MD5, 0, 1, 0, }, {0,CS(SSL_RSA_EXPORT_WITH_RC2_CBC_40_MD5), S_RSA, K_RSA, C_RC2, B_40, M_MD5, 0, 1, 0, }, +{0,CS(SSL_FORTEZZA_DMS_WITH_NULL_SHA), S_KEA, K_KEA, C_NULL,B_0, M_SHA, 0, 1, 0, }, {0,CS(SSL_RSA_WITH_NULL_SHA), S_RSA, K_RSA, C_NULL,B_0, M_SHA, 0, 1, 0, }, {0,CS(SSL_RSA_WITH_NULL_MD5), S_RSA, K_RSA, C_NULL,B_0, M_MD5, 0, 1, 0, }, diff --git a/security/nss/lib/ssl/sslproto.h b/security/nss/lib/ssl/sslproto.h index e7a998126..fa0639605 100644 --- a/security/nss/lib/ssl/sslproto.h +++ b/security/nss/lib/ssl/sslproto.h @@ -139,9 +139,9 @@ #define SSL_DH_ANON_WITH_DES_CBC_SHA 0x001a #define SSL_DH_ANON_WITH_3DES_EDE_CBC_SHA 0x001b -#define SSL_FORTEZZA_DMS_WITH_NULL_SHA 0x001c /* deprecated */ -#define SSL_FORTEZZA_DMS_WITH_FORTEZZA_CBC_SHA 0x001d /* deprecated */ -#define SSL_FORTEZZA_DMS_WITH_RC4_128_SHA 0x001e /* deprecated */ +#define SSL_FORTEZZA_DMS_WITH_NULL_SHA 0x001c +#define SSL_FORTEZZA_DMS_WITH_FORTEZZA_CBC_SHA 0x001d +#define SSL_FORTEZZA_DMS_WITH_RC4_128_SHA 0x001e /* New TLS cipher suites */ #define TLS_RSA_WITH_AES_128_CBC_SHA 0x002F diff --git a/security/nss/lib/ssl/sslsecur.c b/security/nss/lib/ssl/sslsecur.c index 9f537a3ef..404f9a7dc 100644 --- a/security/nss/lib/ssl/sslsecur.c +++ b/security/nss/lib/ssl/sslsecur.c @@ -574,7 +574,12 @@ ssl_FindCertKEAType(CERTCertificate * cert) case SEC_OID_PKCS1_RSA_ENCRYPTION: keaType = kt_rsa; break; - + case SEC_OID_MISSI_KEA_DSS_OLD: + case SEC_OID_MISSI_KEA_DSS: + case SEC_OID_MISSI_DSS_OLD: + case SEC_OID_MISSI_DSS: + keaType = kt_fortezza; + break; case SEC_OID_X942_DIFFIE_HELMAN_KEY: keaType = kt_dh; break; diff --git a/security/nss/lib/ssl/sslsnce.c b/security/nss/lib/ssl/sslsnce.c index a0c164963..345104f1f 100644 --- a/security/nss/lib/ssl/sslsnce.c +++ b/security/nss/lib/ssl/sslsnce.c @@ -147,7 +147,7 @@ struct sidCacheEntryStr { /* 2 */ PRUint16 compression; /* SSL3CompressionMethod */ /*122 */ ssl3SidKeys keys; /* keys and ivs, wrapped as needed. */ -/* 1 */ PRUint8 unused; /* was hasFortezza; */ +/* 1 */ PRUint8 hasFortezza; /* 1 */ PRUint8 resumable; /* 4 */ PRUint32 masterWrapMech; @@ -442,6 +442,7 @@ ConvertFromSID(sidCacheEntry *to, sslSessionID *from) to->u.ssl3.cipherSuite = from->u.ssl3.cipherSuite; to->u.ssl3.compression = (uint16)from->u.ssl3.compression; to->u.ssl3.resumable = from->u.ssl3.resumable; + to->u.ssl3.hasFortezza = from->u.ssl3.hasFortezza; to->u.ssl3.keys = from->u.ssl3.keys; to->u.ssl3.masterWrapMech = from->u.ssl3.masterWrapMech; to->u.ssl3.exchKeyType = from->u.ssl3.exchKeyType; @@ -517,6 +518,7 @@ ConvertToSID(sidCacheEntry *from, certCacheEntry *pcce, to->u.ssl3.cipherSuite = from->u.ssl3.cipherSuite; to->u.ssl3.compression = (SSL3CompressionMethod)from->u.ssl3.compression; to->u.ssl3.resumable = from->u.ssl3.resumable; + to->u.ssl3.hasFortezza = from->u.ssl3.hasFortezza; to->u.ssl3.keys = from->u.ssl3.keys; to->u.ssl3.masterWrapMech = from->u.ssl3.masterWrapMech; to->u.ssl3.exchKeyType = from->u.ssl3.exchKeyType; @@ -542,6 +544,8 @@ ConvertToSID(sidCacheEntry *from, certCacheEntry *pcce, to->u.ssl3.clAuthSeries = 0; to->u.ssl3.clAuthValid = PR_FALSE; + to->u.ssl3.clientWriteSaveLen = 0; + if (from->u.ssl3.certIndex != -1 && pcce) { SECItem derCert; diff --git a/security/nss/lib/ssl/sslsock.c b/security/nss/lib/ssl/sslsock.c index 2e8d73219..9803eec96 100644 --- a/security/nss/lib/ssl/sslsock.c +++ b/security/nss/lib/ssl/sslsock.c @@ -71,6 +71,8 @@ static cipherPolicy ssl_ciphers[] = { /* Export France */ { SSL_EN_RC2_128_CBC_EXPORT40_WITH_MD5, SSL_ALLOWED, SSL_ALLOWED }, { SSL_EN_DES_64_CBC_WITH_MD5, SSL_NOT_ALLOWED, SSL_NOT_ALLOWED }, { SSL_EN_DES_192_EDE3_CBC_WITH_MD5, SSL_NOT_ALLOWED, SSL_NOT_ALLOWED }, + { SSL_FORTEZZA_DMS_WITH_FORTEZZA_CBC_SHA, SSL_NOT_ALLOWED, SSL_NOT_ALLOWED }, + { SSL_FORTEZZA_DMS_WITH_RC4_128_SHA, SSL_NOT_ALLOWED, SSL_NOT_ALLOWED }, { SSL_RSA_WITH_RC4_128_MD5, SSL_RESTRICTED, SSL_NOT_ALLOWED }, { SSL_RSA_WITH_RC4_128_SHA, SSL_RESTRICTED, SSL_NOT_ALLOWED }, { SSL_RSA_FIPS_WITH_3DES_EDE_CBC_SHA, SSL_NOT_ALLOWED, SSL_NOT_ALLOWED }, @@ -79,6 +81,7 @@ static cipherPolicy ssl_ciphers[] = { /* Export France */ { SSL_RSA_WITH_DES_CBC_SHA, SSL_NOT_ALLOWED, SSL_NOT_ALLOWED }, { SSL_RSA_EXPORT_WITH_RC4_40_MD5, SSL_ALLOWED, SSL_ALLOWED }, { SSL_RSA_EXPORT_WITH_RC2_CBC_40_MD5, SSL_ALLOWED, SSL_ALLOWED }, + { SSL_FORTEZZA_DMS_WITH_NULL_SHA, SSL_NOT_ALLOWED, SSL_NOT_ALLOWED }, { SSL_DHE_RSA_WITH_DES_CBC_SHA, SSL_NOT_ALLOWED, SSL_NOT_ALLOWED }, { SSL_DHE_DSS_WITH_DES_CBC_SHA, SSL_NOT_ALLOWED, SSL_NOT_ALLOWED }, { SSL_DHE_RSA_WITH_3DES_EDE_CBC_SHA, SSL_NOT_ALLOWED, SSL_NOT_ALLOWED }, diff --git a/security/nss/lib/ssl/sslt.h b/security/nss/lib/ssl/sslt.h index 052339b7d..0223ee2ad 100644 --- a/security/nss/lib/ssl/sslt.h +++ b/security/nss/lib/ssl/sslt.h @@ -66,7 +66,7 @@ typedef enum { ssl_kea_null = 0, ssl_kea_rsa = 1, ssl_kea_dh = 2, - ssl_kea_fortezza = 3, /* deprecated, now unused */ + ssl_kea_fortezza = 3, ssl_kea_ecdh = 4, ssl_kea_size /* number of ssl_kea_ algorithms */ } SSLKEAType; @@ -79,7 +79,7 @@ typedef enum { #define kt_null ssl_kea_null #define kt_rsa ssl_kea_rsa #define kt_dh ssl_kea_dh -#define kt_fortezza ssl_kea_fortezza /* deprecated, now unused */ +#define kt_fortezza ssl_kea_fortezza #define kt_ecdh ssl_kea_ecdh #define kt_kea_size ssl_kea_size @@ -105,7 +105,7 @@ typedef enum { ssl_calg_des = 3, ssl_calg_3des = 4, ssl_calg_idea = 5, - ssl_calg_fortezza = 6, /* deprecated, now unused */ + ssl_calg_fortezza = 6, /* skipjack */ ssl_calg_aes = 7 /* coming soon */ } SSLCipherAlgorithm; |