From c143cc80be3f0ebb7a5ec566552502916619f333 Mon Sep 17 00:00:00 2001 From: "wtc%google.com" Date: Sat, 2 Feb 2008 00:03:09 +0000 Subject: Bug 403563: checked in Nagendra's proposed patch v5, plus - shorten SSL_ENABLE_SESSION_TICKET_EXTENSION to SSL_ENABLE_SESSION_TICKETS - fix compiler warnings about PK11_CipherOp calls Modified Files: Tag: NSS_RFC4507BIS_BRANCH cmd/selfserv/selfserv.c cmd/strsclnt/strsclnt.c cmd/tstclnt/tstclnt.c lib/ssl/ssl.h lib/ssl/ssl3ext.c lib/ssl/ssl3prot.h lib/ssl/sslimpl.h lib/ssl/sslsnce.c lib/ssl/sslsock.c --- security/nss/cmd/selfserv/selfserv.c | 2 +- security/nss/cmd/strsclnt/strsclnt.c | 4 +- security/nss/cmd/tstclnt/tstclnt.c | 2 +- security/nss/lib/ssl/ssl.h | 4 +- security/nss/lib/ssl/ssl3ext.c | 181 ++++++++++++++++++---------- security/nss/lib/ssl/ssl3prot.h | 6 +- security/nss/lib/ssl/sslimpl.h | 10 +- security/nss/lib/ssl/sslsnce.c | 225 ++++++++++++++++++++++++++++++++++- security/nss/lib/ssl/sslsock.c | 8 +- 9 files changed, 363 insertions(+), 79 deletions(-) diff --git a/security/nss/cmd/selfserv/selfserv.c b/security/nss/cmd/selfserv/selfserv.c index d70743c65..09dc360d7 100644 --- a/security/nss/cmd/selfserv/selfserv.c +++ b/security/nss/cmd/selfserv/selfserv.c @@ -1451,7 +1451,7 @@ server_main( } } if (enableSessionTicketExtension) { - rv = SSL_OptionSet(model_sock, SSL_ENABLE_SESSION_TICKET_EXTENSION, + rv = SSL_OptionSet(model_sock, SSL_ENABLE_SESSION_TICKETS, PR_TRUE); if (rv != SECSuccess) { errExit("error enabling Session Ticket extension "); diff --git a/security/nss/cmd/strsclnt/strsclnt.c b/security/nss/cmd/strsclnt/strsclnt.c index 540b8bafc..61d33da0d 100644 --- a/security/nss/cmd/strsclnt/strsclnt.c +++ b/security/nss/cmd/strsclnt/strsclnt.c @@ -1238,9 +1238,9 @@ client_main( if (enableSessionTicketExtension) { rv = SSL_OptionSet(model_sock, - SSL_ENABLE_SESSION_TICKET_EXTENSION, PR_TRUE); + SSL_ENABLE_SESSION_TICKETS, PR_TRUE); if (rv != SECSuccess) - errExit("SSL_OptionSet SSL_ENABLE_SESSION_TICKET_EXTENSION"); + errExit("SSL_OptionSet SSL_ENABLE_SESSION_TICKETS"); } SSL_SetURL(model_sock, hostName); diff --git a/security/nss/cmd/tstclnt/tstclnt.c b/security/nss/cmd/tstclnt/tstclnt.c index 5a4172d37..aa576573f 100644 --- a/security/nss/cmd/tstclnt/tstclnt.c +++ b/security/nss/cmd/tstclnt/tstclnt.c @@ -837,7 +837,7 @@ int main(int argc, char **argv) } /* enable Session Ticket extension. */ - rv = SSL_OptionSet(s, SSL_ENABLE_SESSION_TICKET_EXTENSION, + rv = SSL_OptionSet(s, SSL_ENABLE_SESSION_TICKETS, enableSessionTicketExtension); if (rv != SECSuccess) { SECU_PrintError(progName, "error enabling Session Ticket extension"); diff --git a/security/nss/lib/ssl/ssl.h b/security/nss/lib/ssl/ssl.h index 06179409d..a0811c8ce 100644 --- a/security/nss/lib/ssl/ssl.h +++ b/security/nss/lib/ssl/ssl.h @@ -112,8 +112,8 @@ SSL_IMPORT PRFileDesc *SSL_ImportFD(PRFileDesc *model, PRFileDesc *fd); /* step-down keys if needed. */ #define SSL_BYPASS_PKCS11 16 /* use PKCS#11 for pub key only */ #define SSL_NO_LOCKS 17 /* Don't use locks for protection */ -#define SSL_ENABLE_SESSION_TICKET_EXTENSION 18 /* Enable TLS1 SessionTicket * - * extension (off by default) */ +#define SSL_ENABLE_SESSION_TICKETS 18 /* Enable TLS1 SessionTicket * + * extension (off by default) */ #ifdef SSL_DEPRECATED_FUNCTION /* Old deprecated function names */ diff --git a/security/nss/lib/ssl/ssl3ext.c b/security/nss/lib/ssl/ssl3ext.c index 6f47b6ff9..27c47b245 100644 --- a/security/nss/lib/ssl/ssl3ext.c +++ b/security/nss/lib/ssl/ssl3ext.c @@ -50,12 +50,14 @@ #include "pk11pub.h" #include "blapi.h" +static uint8 key_name[SESS_TICKET_KEY_NAME_LEN]; static PK11SymKey *session_ticket_enc_key_pkcs11 = NULL; static PK11SymKey *session_ticket_mac_key_pkcs11 = NULL; -static PRCallOnceType generate_session_keys_once_pkcs11; static unsigned char session_ticket_enc_key[32]; static unsigned char session_ticket_mac_key[SHA256_LENGTH]; + +static PRBool session_ticket_keys_initialized = PR_FALSE; static PRCallOnceType generate_session_keys_once; static PRInt32 ssl3_SendServerNameExt(sslSocket * ss, @@ -66,7 +68,11 @@ static SECStatus ssl3_AppendToItem(SECItem *item, const unsigned char *buf, PRUint32 bytes); static SECStatus ssl3_AppendNumberToItem(SECItem *item, PRUint32 num, PRInt32 lenSize); - +static SECStatus ssl3_GetSessionTicketKeysPKCS11(sslSocket *ss, + PK11SymKey **aes_key, PK11SymKey **mac_key); +static SECStatus ssl3_GetSessionTicketKeys(const unsigned char **aes_key, + PRUint32 *aes_key_length, const unsigned char **mac_key, + PRUint32 *mac_key_length); /* * Write bytes. Using this function means the SECItem structure @@ -121,37 +127,38 @@ static SECStatus ssl3_SessionTicketShutdown(void* appData, void* nssData) PK11_FreeSymKey(session_ticket_mac_key_pkcs11); session_ticket_mac_key_pkcs11 = NULL; } - memset(&generate_session_keys_once_pkcs11, 0, sizeof(PRCallOnceType)); + PORT_Memset(&generate_session_keys_once, 0, + sizeof(generate_session_keys_once)); return SECSuccess; } + static PRStatus -ssl3_GenerateSessionTicketKeysPKCS11(void) +ssl3_GenerateSessionTicketKeysPKCS11(void *data) { - PK11SlotInfo *slot; SECStatus rv; - CK_MECHANISM_TYPE mechanism_array[2]; - - slot = PK11_GetBestSlot(CKM_AES_CBC, NULL); - /* no parameter, 128-bit key size */ - session_ticket_enc_key_pkcs11 = - PK11_KeyGen(slot, CKM_AES_KEY_GEN, NULL, 16, NULL); - PK11_FreeSlot(slot); - if (!session_ticket_enc_key_pkcs11) - return PR_FAILURE; + sslSocket *ss = (sslSocket *)data; + SECKEYPrivateKey *svrPrivKey = ss->serverCerts[kt_rsa].SERVERKEY; + SECKEYPublicKey *svrPubKey = ss->serverCerts[kt_rsa].serverKeyPair->pubKey; - mechanism_array[0] = CKM_SHA256_HMAC; - mechanism_array[1] = CKM_GENERIC_SECRET_KEY_GEN; - slot = PK11_GetBestSlotMultiple(mechanism_array, 2, NULL); - /* no parameter, 256-bit key size */ - session_ticket_mac_key_pkcs11 = - PK11_KeyGen(slot, CKM_GENERIC_SECRET_KEY_GEN, NULL, 32, NULL); - PK11_FreeSlot(slot); - if (!session_ticket_mac_key_pkcs11) + if (svrPrivKey == NULL || svrPubKey == NULL) { + SSL_DBG(("%d: SSL[%d]: Pub or priv key(s) is NULL.", + SSL_GETPID(), ss->fd)); goto loser; + } + + /* Get a copy of the session keys from shared memory. */ + PORT_Memcpy(key_name, SESS_TICKET_KEY_NAME_PREFIX, + sizeof(SESS_TICKET_KEY_NAME_PREFIX)); + if (!ssl_GetSessionTicketKeysPKCS11(svrPrivKey, svrPubKey, ss->pkcs11PinArg, + &key_name[4], &session_ticket_enc_key_pkcs11, + &session_ticket_mac_key_pkcs11)) + return PR_FAILURE; + rv = NSS_RegisterShutdown(ssl3_SessionTicketShutdown, NULL); if (rv != SECSuccess) goto loser; + return PR_SUCCESS; loser: @@ -159,41 +166,47 @@ loser: return PR_FAILURE; } -SECStatus -ssl3_GetSessionTicketKeysPKCS11(PK11SymKey **aes_key, PK11SymKey **mac_key) +static SECStatus +ssl3_GetSessionTicketKeysPKCS11(sslSocket *ss, PK11SymKey **aes_key, + PK11SymKey **mac_key) { - PRStatus rv; - rv = PR_CallOnce(&generate_session_keys_once_pkcs11, - ssl3_GenerateSessionTicketKeysPKCS11); - if (rv != PR_SUCCESS) + if (PR_CallOnceWithArg(&generate_session_keys_once, + ssl3_GenerateSessionTicketKeysPKCS11, ss) != PR_SUCCESS) + return SECFailure; + + if (session_ticket_enc_key_pkcs11 == NULL || + session_ticket_mac_key_pkcs11 == NULL) return SECFailure; *aes_key = session_ticket_enc_key_pkcs11; *mac_key = session_ticket_mac_key_pkcs11; - return SECSuccess; } static PRStatus ssl3_GenerateSessionTicketKeys(void) { - SECStatus rv = PK11_GenerateRandom(session_ticket_enc_key, - sizeof(session_ticket_enc_key)); - if (rv != SECSuccess) return PR_FAILURE; - rv = PK11_GenerateRandom(session_ticket_mac_key, - sizeof(session_ticket_mac_key)); - return rv == SECSuccess ? PR_SUCCESS : PR_FAILURE; + PORT_Memcpy(key_name, SESS_TICKET_KEY_NAME_PREFIX, + sizeof(SESS_TICKET_KEY_NAME_PREFIX)); + + if (!ssl_GetSessionTicketKeys(&key_name[4], session_ticket_enc_key, + session_ticket_mac_key)) + return PR_FAILURE; + + session_ticket_keys_initialized = PR_TRUE; + return PR_SUCCESS; } -SECStatus +static SECStatus ssl3_GetSessionTicketKeys(const unsigned char **aes_key, PRUint32 *aes_key_length, const unsigned char **mac_key, PRUint32 *mac_key_length) { - PRStatus rv; - rv = PR_CallOnce(&generate_session_keys_once, - ssl3_GenerateSessionTicketKeys); - if (rv != PR_SUCCESS) + if (PR_CallOnce(&generate_session_keys_once, + ssl3_GenerateSessionTicketKeys) != SECSuccess) + return SECFailure; + + if (!session_ticket_keys_initialized) return SECFailure; *aes_key = session_ticket_enc_key; @@ -462,7 +475,7 @@ ssl3_SendNewSessionTicket(sslSocket *ss) rv = ssl3_GetSessionTicketKeys(&aes_key, &aes_key_length, &mac_key, &mac_key_length); } else { - rv = ssl3_GetSessionTicketKeysPKCS11(&aes_key_pkcs11, + rv = ssl3_GetSessionTicketKeysPKCS11(ss, &aes_key_pkcs11, &mac_key_pkcs11); } if (rv != SECSuccess) goto loser; @@ -521,7 +534,7 @@ ssl3_SendNewSessionTicket(sslSocket *ss) message_length = sizeof(ticket.ticket_lifetime_hint) /* ticket_lifetime_hint */ + 2 /* length field for NewSessionTicket.ticket */ - + sizeof(TLS1_EX_SESS_TICKET_KEY_NAME) /* key_name */ + + SESS_TICKET_KEY_NAME_LEN /* key_name */ + AES_BLOCK_SIZE /* iv */ + 2 /* length field for NewSessionTicket.ticket.encrypted_state */ + ciphertext_length /* encrypted_state */ @@ -621,7 +634,7 @@ ssl3_SendNewSessionTicket(sslSocket *ss) if (!aes_ctx_pkcs11) goto loser; - rv = PK11_CipherOp(aes_ctx_pkcs11, ciphertext.data, &ciphertext.len, + rv = PK11_CipherOp(aes_ctx_pkcs11, ciphertext.data, (int *)&ciphertext.len, ciphertext.len, plaintext_item.data, plaintext_item.len); PK11_Finalize(aes_ctx_pkcs11); PK11_DestroyContext(aes_ctx_pkcs11, PR_TRUE); @@ -641,8 +654,7 @@ ssl3_SendNewSessionTicket(sslSocket *ss) goto loser; HMAC_Begin(hmac_ctx); - HMAC_Update(hmac_ctx, (unsigned char *)TLS1_EX_SESS_TICKET_KEY_NAME, - sizeof(TLS1_EX_SESS_TICKET_KEY_NAME)); + HMAC_Update(hmac_ctx, key_name, SESS_TICKET_KEY_NAME_LEN); HMAC_Update(hmac_ctx, iv, sizeof(iv)); HMAC_Update(hmac_ctx, (unsigned char *)length_buf, 2); HMAC_Update(hmac_ctx, ciphertext.data, ciphertext.len); @@ -658,9 +670,8 @@ ssl3_SendNewSessionTicket(sslSocket *ss) goto loser; rv = PK11_DigestBegin(hmac_ctx_pkcs11); - rv = PK11_DigestOp(hmac_ctx_pkcs11, - (unsigned char *)TLS1_EX_SESS_TICKET_KEY_NAME, - sizeof(TLS1_EX_SESS_TICKET_KEY_NAME)); + rv = PK11_DigestOp(hmac_ctx_pkcs11, key_name, + SESS_TICKET_KEY_NAME_LEN); rv = PK11_DigestOp(hmac_ctx_pkcs11, iv, sizeof(iv)); rv = PK11_DigestOp(hmac_ctx_pkcs11, (unsigned char *)length_buf, 2); rv = PK11_DigestOp(hmac_ctx_pkcs11, ciphertext.data, ciphertext.len); @@ -682,9 +693,7 @@ ssl3_SendNewSessionTicket(sslSocket *ss) message_length - sizeof(ticket.ticket_lifetime_hint) - 2, 2); if (rv != SECSuccess) goto loser; - rv = ssl3_AppendHandshake(ss, - (unsigned char *)TLS1_EX_SESS_TICKET_KEY_NAME, - sizeof(TLS1_EX_SESS_TICKET_KEY_NAME)); + rv = ssl3_AppendHandshake(ss, key_name, SESS_TICKET_KEY_NAME_LEN); if (rv != SECSuccess) goto loser; rv = ssl3_AppendHandshake(ss, iv, sizeof(iv)); @@ -750,6 +759,12 @@ ssl3_ServerHandleSessionTicketExt(sslSocket *ss, PRUint16 ex_type, unsigned char computed_mac[TLS1_EX_SESS_TICKET_MAC_LENGTH]; unsigned int computed_mac_length; const SECHashObject *hashObj; + const unsigned char *aes_key; + const unsigned char *mac_key; + PK11SymKey *aes_key_pkcs11; + PK11SymKey *mac_key_pkcs11; + PRUint32 aes_key_length; + PRUint32 mac_key_length; PRUint64 hmac_ctx_buf[MAX_MAC_CONTEXT_LLONGS]; HMACContext *hmac_ctx; PK11Context *hmac_ctx_pkcs11; @@ -783,13 +798,37 @@ ssl3_ServerHandleSessionTicketExt(sslSocket *ss, PRUint16 ex_type, != SECSuccess) return SECFailure; + /* Get session ticket keys. */ + if (ss->opt.bypassPKCS11) { + rv = ssl3_GetSessionTicketKeys(&aes_key, &aes_key_length, + &mac_key, &mac_key_length); + } else { + rv = ssl3_GetSessionTicketKeysPKCS11(ss, &aes_key_pkcs11, + &mac_key_pkcs11); + } + if (rv != SECSuccess) { + SSL_DBG(("%d: SSL[%d]: Unable to get/generate session ticket keys.", + SSL_GETPID(), ss->fd)); + goto no_ticket; + } + + /* If the ticket sent by the client was generated under a key different + * from the one we have, bypass ticket processing. + */ + if (PORT_Memcmp(enc_session_ticket.key_name, key_name, + SESS_TICKET_KEY_NAME_LEN) != 0) { + SSL_DBG(("%d: SSL[%d]: Session ticket key_name sent mismatch.", + SSL_GETPID(), ss->fd)); + goto no_ticket; + } + /* Verify the MAC on the ticket. MAC verification may also * fail if the MAC key has been recently refreshed. */ if (ss->opt.bypassPKCS11) { hmac_ctx = (HMACContext *)hmac_ctx_buf; hashObj = HASH_GetRawHashObject(HASH_AlgSHA256); - if (HMAC_Init(hmac_ctx, hashObj, session_ticket_mac_key, + if (HMAC_Init(hmac_ctx, hashObj, mac_key, sizeof(session_ticket_mac_key), PR_FALSE) != SECSuccess) goto no_ticket; HMAC_Begin(hmac_ctx); @@ -803,9 +842,15 @@ ssl3_ServerHandleSessionTicketExt(sslSocket *ss, PRUint16 ex_type, macParam.data = NULL; macParam.len = 0; hmac_ctx_pkcs11 = PK11_CreateContextBySymKey(macMech, - CKA_SIGN, session_ticket_mac_key_pkcs11, &macParam); - if (!hmac_ctx_pkcs11) + CKA_SIGN, mac_key_pkcs11, &macParam); + if (!hmac_ctx_pkcs11) { + SSL_DBG(("%d: SSL[%d]: Unable to create HMAC context: %d.", + SSL_GETPID(), ss->fd, PORT_GetError())); goto no_ticket; + } else { + SSL_DBG(("%d: SSL[%d]: Successfully created HMAC context.", + SSL_GETPID(), ss->fd)); + } rv = PK11_DigestBegin(hmac_ctx_pkcs11); rv = PK11_DigestOp(hmac_ctx_pkcs11, extension_data.data, extension_data.len - TLS1_EX_SESS_TICKET_MAC_LENGTH); @@ -820,8 +865,11 @@ ssl3_ServerHandleSessionTicketExt(sslSocket *ss, PRUint16 ex_type, goto no_ticket; } if (PORT_Memcmp(computed_mac, enc_session_ticket.mac, - computed_mac_length) != 0) + computed_mac_length) != 0) { + SSL_DBG(("%d: SSL[%d]: Session ticket MAC mismatch.", + SSL_GETPID(), ss->fd)); goto no_ticket; + } /* We ignore key_name for now. * This is ok as MAC verification succeeded. @@ -835,11 +883,14 @@ ssl3_ServerHandleSessionTicketExt(sslSocket *ss, PRUint16 ex_type, if (ss->opt.bypassPKCS11) { aes_ctx = (AESContext *)aes_ctx_buf; - rv = AES_InitContext(aes_ctx, session_ticket_enc_key, + rv = AES_InitContext(aes_ctx, aes_key, sizeof(session_ticket_enc_key), enc_session_ticket.iv, NSS_AES_CBC, 0,AES_BLOCK_SIZE); - if (rv != SECSuccess) + if (rv != SECSuccess) { + SSL_DBG(("%d: SSL[%d]: Unable to create AES context.", + SSL_GETPID(), ss->fd)); goto no_ticket; + } rv = AES_Decrypt(aes_ctx, decrypted_state->data, &decrypted_state->len, decrypted_state->len, @@ -852,12 +903,15 @@ ssl3_ServerHandleSessionTicketExt(sslSocket *ss, PRUint16 ex_type, ivItem.data = enc_session_ticket.iv; ivItem.len = AES_BLOCK_SIZE; aes_ctx_pkcs11 = PK11_CreateContextBySymKey(cipherMech, - CKA_DECRYPT, session_ticket_enc_key_pkcs11, &ivItem); - if (!aes_ctx_pkcs11) + CKA_DECRYPT, aes_key_pkcs11, &ivItem); + if (!aes_ctx_pkcs11) { + SSL_DBG(("%d: SSL[%d]: Unable to create AES context.", + SSL_GETPID(), ss->fd)); goto no_ticket; + } rv = PK11_CipherOp(aes_ctx_pkcs11, decrypted_state->data, - &decrypted_state->len, decrypted_state->len, + (int *)&decrypted_state->len, decrypted_state->len, enc_session_ticket.encrypted_state.data, enc_session_ticket.encrypted_state.len); PK11_Finalize(aes_ctx_pkcs11); @@ -985,7 +1039,8 @@ ssl3_ServerHandleSessionTicketExt(sslSocket *ss, PRUint16 ex_type, * memory since the ticket is of no use. */ if (parsed_session_ticket->timestamp != 0 && - parsed_session_ticket->timestamp + TLS1_EX_SESS_TICKET_LIFETIME_HINT > ssl_Time()) { + parsed_session_ticket->timestamp + + TLS1_EX_SESS_TICKET_LIFETIME_HINT > ssl_Time()) { sid = ssl3_NewSessionID(ss, PR_TRUE); if (sid == NULL) { @@ -1039,6 +1094,8 @@ ssl3_ServerHandleSessionTicketExt(sslSocket *ss, PRUint16 ex_type, if (0) { no_ticket: + SSL_DBG(("%d: SSL[%d]: Session ticket parsing failed.", + SSL_GETPID(), ss->fd)); if (sid) { ssl_FreeSID(sid); sid = NULL; @@ -1084,7 +1141,7 @@ ssl3_ParseEncryptedSessionTicket(sslSocket *ss, SECItem *data, EncryptedSessionTicket *enc_session_ticket) { if (ssl3_ConsumeFromItem(data, &enc_session_ticket->key_name, - sizeof(TLS1_EX_SESS_TICKET_KEY_NAME)) != SECSuccess) + SESS_TICKET_KEY_NAME_LEN) != SECSuccess) return SECFailure; if (ssl3_ConsumeFromItem(data, &enc_session_ticket->iv, AES_BLOCK_SIZE) != SECSuccess) diff --git a/security/nss/lib/ssl/ssl3prot.h b/security/nss/lib/ssl/ssl3prot.h index 83ab67e7d..e45d18bd7 100644 --- a/security/nss/lib/ssl/ssl3prot.h +++ b/security/nss/lib/ssl/ssl3prot.h @@ -333,6 +333,10 @@ typedef struct { } identity; } ClientIdentity; +#define SESS_TICKET_KEY_NAME_PREFIX "NSS!" +#define SESS_TICKET_KEY_NAME_LEN 16 +#define SESS_TICKET_KEY_VAR_NAME_LEN 12 + typedef struct { unsigned char *key_name; unsigned char *iv; @@ -350,7 +354,7 @@ typedef enum { session_ticket_xtn = 35 } ExtensionType; -#define TLS1_EX_SESS_TICKET_KEY_NAME "NSS_SESS_TICKET!" + #define TLS1_EX_SESS_TICKET_MAC_LENGTH 32 #endif /* __ssl3proto_h_ */ diff --git a/security/nss/lib/ssl/sslimpl.h b/security/nss/lib/ssl/sslimpl.h index f9f2c33e1..7aacf4f98 100644 --- a/security/nss/lib/ssl/sslimpl.h +++ b/security/nss/lib/ssl/sslimpl.h @@ -1479,14 +1479,14 @@ extern SECStatus ssl3_HandleHelloExtensions(sslSocket *ss, /* Hello Extension related routines. */ extern PRBool ssl3_ClientExtensionAdvertised(sslSocket *ss, PRUint16 ex_type); extern PRBool ssl3_ExtensionNegotiated(sslSocket *ss, PRUint16 ex_type); -extern SECStatus ssl3_GetSessionTicketKeysPKCS11(PK11SymKey **aes_key, - PK11SymKey **mac_key); -extern SECStatus ssl3_GetSessionTicketKeys(const unsigned char **aes_key, - PRUint32 *aes_key_length, const unsigned char **mac_key, - PRUint32 *mac_key_length); extern SECStatus ssl3_SetSIDSessionTicket(sslSessionID *sid, NewSessionTicket *session_ticket); extern SECStatus ssl3_SendNewSessionTicket(sslSocket *ss); +extern PRBool ssl_GetSessionTicketKeys(uint8 *key_name, unsigned char *encKey, + unsigned char *macKey); +extern PRBool ssl_GetSessionTicketKeysPKCS11(SECKEYPrivateKey *svrPrivKey, + SECKEYPublicKey *svrPubKey, void *pwArg, unsigned char *keyName, + PK11SymKey **aesKey, PK11SymKey **macKey); /* Tell clients to consider tickets valid for this long. */ #define TLS1_EX_SESS_TICKET_LIFETIME_HINT (2 * 24 * 60 * 60) /* 2 days */ diff --git a/security/nss/lib/ssl/sslsnce.c b/security/nss/lib/ssl/sslsnce.c index f4df588e8..b5a7279ba 100644 --- a/security/nss/lib/ssl/sslsnce.c +++ b/security/nss/lib/ssl/sslsnce.c @@ -67,6 +67,10 @@ * sidCacheEntry sidCacheData[ numSIDCacheEntries]; * certCacheEntry certCacheData[numCertCacheEntries]; * SSLWrappedSymWrappingKey keyCacheData[kt_kea_size][SSL_NUM_WRAP_MECHS]; + * uint8 keyNameSuffix[SESS_TICKET_KEY_VAR_NAME_LEN] + * encKeyCacheEntry ticketEncKey; // Wrapped in non-bypass mode + * encKeyCacheEntry ticketMacKey; // Wrapped in non-bypass mode + * PRBool ticketKeysValid; * } cacheMemCacheData; */ #include "nssrenam.h" @@ -80,6 +84,7 @@ #include "sslproto.h" #include "pk11func.h" #include "base64.h" +#include "keyhi.h" #include @@ -177,6 +182,12 @@ struct sidCacheSetStr { }; typedef struct sidCacheSetStr sidCacheSet; +struct encKeyCacheEntryStr { + PRUint8 bytes[512]; + PRInt32 length; +}; +typedef struct encKeyCacheEntryStr encKeyCacheEntry; + struct cacheDescStr { PRUint32 cacheMemSize; @@ -213,6 +224,10 @@ struct cacheDescStr { sidCacheEntry * sidCacheData; certCacheEntry * certCacheData; SSLWrappedSymWrappingKey * keyCacheData; + uint8 * ticketKeyNameSuffix; + encKeyCacheEntry * ticketEncKey; + encKeyCacheEntry * ticketMacKey; + PRUint32 * ticketKeysValid; /* Only the private copies of these pointers are valid */ char * cacheMem; @@ -998,9 +1013,27 @@ InitCache(cacheDesc *cache, int maxCacheEntries, PRUint32 ssl2_timeout, ptr = (ptrdiff_t)(cache->keyCacheData + cache->numKeyCacheEntries); ptr = SID_ROUNDUP(ptr, SID_ALIGNMENT); + cache->keyCacheSize = (char *)ptr - (char *)cache->keyCacheData; + + cache->ticketKeyNameSuffix = (uint8 *)ptr; + ptr = (ptrdiff_t)(cache->ticketKeyNameSuffix + + SESS_TICKET_KEY_VAR_NAME_LEN); + ptr = SID_ROUNDUP(ptr, SID_ALIGNMENT); + + cache->ticketEncKey = (encKeyCacheEntry *)ptr; + ptr = (ptrdiff_t)(cache->ticketEncKey + 1); + ptr = SID_ROUNDUP(ptr, SID_ALIGNMENT); + + cache->ticketMacKey = (encKeyCacheEntry *)ptr; + ptr = (ptrdiff_t)(cache->ticketMacKey + 1); + ptr = SID_ROUNDUP(ptr, SID_ALIGNMENT); + + cache->ticketKeysValid = (PRUint32 *)ptr; + ptr = (ptrdiff_t)(cache->ticketKeysValid + 1); + ptr = SID_ROUNDUP(ptr, SID_ALIGNMENT); + cache->cacheMemSize = ptr; - cache->keyCacheSize = (char *)ptr - (char *)cache->keyCacheData; if (ssl2_timeout) { if (ssl2_timeout > MAX_SSL2_TIMEOUT) { @@ -1087,6 +1120,10 @@ InitCache(cacheDesc *cache, int maxCacheEntries, PRUint32 ssl2_timeout, *(ptrdiff_t *)(&cache->sidCacheData ) += ptr; *(ptrdiff_t *)(&cache->certCacheData) += ptr; *(ptrdiff_t *)(&cache->keyCacheData ) += ptr; + *(ptrdiff_t *)(&cache->ticketKeyNameSuffix) += ptr; + *(ptrdiff_t *)(&cache->ticketEncKey) += ptr; + *(ptrdiff_t *)(&cache->ticketMacKey) += ptr; + *(ptrdiff_t *)(&cache->ticketKeysValid) += ptr; /* initialize the locks */ init_time = ssl_Time(); @@ -1366,6 +1403,10 @@ SSL_InheritMPServerSIDCacheInstance(cacheDesc *cache, const char * envString) *(ptrdiff_t *)(&cache->sidCacheData ) += ptr; *(ptrdiff_t *)(&cache->certCacheData) += ptr; *(ptrdiff_t *)(&cache->keyCacheData ) += ptr; + *(ptrdiff_t *)(&cache->ticketKeyNameSuffix) += ptr; + *(ptrdiff_t *)(&cache->ticketEncKey) += ptr; + *(ptrdiff_t *)(&cache->ticketMacKey) += ptr; + *(ptrdiff_t *)(&cache->ticketKeysValid) += ptr; cache->cacheMemMap = my.cacheMemMap; cache->cacheMem = my.cacheMem; @@ -1596,6 +1637,188 @@ ssl_GetWrappingKey( PRInt32 symWrapMechIndex, return rv; } +PRBool +ssl_GetSessionTicketKeys(uint8 *keyName, unsigned char *encKey, + unsigned char *macKey) +{ + PRBool rv = PR_FALSE; + PRUint32 now = 0; + cacheDesc *cache = &globalCache; + + /* Grab lock. */ + now = LockSidCacheLock(cache->keyCacheLock, now); + if (!now) + return rv; + + if (!*(cache->ticketKeysValid)) { + if (PK11_GenerateRandom(cache->ticketKeyNameSuffix, + SESS_TICKET_KEY_VAR_NAME_LEN) != SECSuccess) + goto loser; + if (PK11_GenerateRandom(cache->ticketEncKey->bytes, 32) != SECSuccess) + goto loser; + if (PK11_GenerateRandom(cache->ticketMacKey->bytes, + SHA256_LENGTH) != SECSuccess) + goto loser; + *(cache->ticketKeysValid) = 1; + } + + rv = PR_TRUE; + + loser: + UnlockSidCacheLock(cache->keyCacheLock); + if (*(cache->ticketKeysValid)) { + PORT_Memcpy(keyName, cache->ticketKeyNameSuffix, + SESS_TICKET_KEY_VAR_NAME_LEN); + PORT_Memcpy(encKey, cache->ticketEncKey->bytes, 32); + PORT_Memcpy(macKey, cache->ticketMacKey->bytes, SHA256_LENGTH); + return PR_TRUE; + } + return rv; +} + +PRBool +ssl_GetSessionTicketKeysPKCS11(SECKEYPrivateKey *svrPrivKey, + SECKEYPublicKey *svrPubKey, void *pwArg, unsigned char *keyName, + PK11SymKey **aesKey, PK11SymKey **macKey) +{ + PK11SlotInfo *slot; + PRUint32 now = 0; + CK_MECHANISM_TYPE mechanismArray[2]; + PK11SymKey *aesKeyTmp = NULL; + PK11SymKey *macKeyTmp = NULL; + SECItem wrappedAesKey = {siBuffer, NULL, 0}; + SECItem wrappedMacKey = {siBuffer, NULL, 0}; + PRStatus rv = SECFailure; + cacheDesc *cache = &globalCache; + + /* No need to grab a lock, we are reading. */ + if (*(cache->ticketKeysValid)) { + wrappedAesKey.type = siBuffer; + wrappedAesKey.data = cache->ticketEncKey->bytes; + wrappedAesKey.len = cache->ticketEncKey->length; + PORT_Assert(wrappedAesKey.len <= sizeof(cache->ticketEncKey->bytes)); + aesKeyTmp = PK11_PubUnwrapSymKey(svrPrivKey, &wrappedAesKey, + CKM_AES_CBC, CKA_DECRYPT, 0); + + wrappedMacKey.type = siBuffer; + wrappedMacKey.data = cache->ticketMacKey->bytes; + wrappedMacKey.len = cache->ticketMacKey->length; + PORT_Assert(wrappedMacKey.len <= sizeof(cache->ticketMacKey->bytes)); + macKeyTmp = PK11_PubUnwrapSymKey(svrPrivKey, &wrappedMacKey, + CKM_SHA256_HMAC, CKA_SIGN, 0); + + if (aesKeyTmp == NULL || macKeyTmp == NULL) { + if (aesKeyTmp) + PK11_FreeSymKey(aesKeyTmp); + if (macKeyTmp) + PK11_FreeSymKey(macKeyTmp); + SSL_DBG(("%d: SSL[%s]: Unable to unwrap session ticket keys.", + SSL_GETPID(), "unknown")); + return PR_FALSE; + } else { + PORT_Memcpy(keyName, cache->ticketKeyNameSuffix, + SESS_TICKET_KEY_VAR_NAME_LEN); + *aesKey = aesKeyTmp; + *macKey = macKeyTmp; + SSL_DBG(("%d: SSL[%s]: Successfully unwrapped session ticket keys.", + SSL_GETPID(), "unknown")); + return PR_TRUE; + } + } + + /* Keys do not exist, create them. */ + now = LockSidCacheLock(cache->keyCacheLock, now); + if (!now) { + SSL_DBG(("%d: SSL[%s]: Unable to grab keyCacheLock.", + SSL_GETPID(), "unknown")); + return PR_FALSE; + } + + if (PK11_GenerateRandom(cache->ticketKeyNameSuffix, + SESS_TICKET_KEY_VAR_NAME_LEN) != SECSuccess) { + SSL_DBG(("%d: SSL[%s]: Unable to generate random key_name bytes.", + SSL_GETPID(), "unknown")); + goto loser; + } + + mechanismArray[0] = CKM_AES_CBC; + mechanismArray[1] = CKM_SHA256_HMAC; + + slot = PK11_GetBestSlotMultiple(mechanismArray, 2, pwArg); + aesKeyTmp = PK11_KeyGen(slot, mechanismArray[0], NULL, 32, pwArg); + macKeyTmp = PK11_KeyGen(slot, mechanismArray[1], NULL, SHA256_LENGTH, pwArg); + PK11_FreeSlot(slot); + + if (aesKeyTmp == NULL || macKeyTmp == NULL) { + SSL_DBG(("%d: SSL[%s]: Unable to generate session ticket keys.", + SSL_GETPID(), "unknown")); + goto loser; + } + + /* Export the keys to the shared cache in wrapped form. */ + wrappedAesKey.len = SECKEY_PublicKeyStrength(svrPubKey); + PORT_Assert(wrappedAesKey.len <= sizeof(cache->ticketEncKey->bytes)); + if (wrappedAesKey.len > sizeof(cache->ticketEncKey->bytes)) + goto loser; + wrappedAesKey.data = (unsigned char*)PORT_Alloc(wrappedAesKey.len); + + if (PK11_PubWrapSymKey(CKM_RSA_PKCS, svrPubKey, + aesKeyTmp, &wrappedAesKey) != SECSuccess) { + SSL_DBG(("%d: SSL[%s]: Unable to wrap session ticket enc key.", + SSL_GETPID(), "unknown")); + goto loser; + } + + wrappedMacKey.len = SECKEY_PublicKeyStrength(svrPubKey); + PORT_Assert(wrappedMacKey.len <= sizeof(cache->ticketMacKey->bytes)); + if (wrappedMacKey.len > sizeof(cache->ticketMacKey->bytes)) + goto loser; + wrappedMacKey.data = (unsigned char*)PORT_Alloc(wrappedMacKey.len); + + if (PK11_PubWrapSymKey(CKM_RSA_PKCS, svrPubKey, + macKeyTmp, &wrappedMacKey) != SECSuccess) { + SSL_DBG(("%d: SSL[%s]: Unable to wrap session ticket mac key.", + SSL_GETPID(), "unknown")); + goto loser; + } + + cache->ticketEncKey->length = wrappedAesKey.len; + cache->ticketMacKey->length = wrappedMacKey.len; + + PORT_Memcpy(cache->ticketEncKey->bytes, wrappedAesKey.data, + wrappedAesKey.len); + PORT_Memcpy(cache->ticketMacKey->bytes, wrappedMacKey.data, + wrappedMacKey.len); + *(cache->ticketKeysValid) = 1; + + PORT_Memcpy(keyName, cache->ticketKeyNameSuffix, + SESS_TICKET_KEY_VAR_NAME_LEN); + *aesKey = aesKeyTmp; + *macKey = macKeyTmp; + rv = SECSuccess; + + loser: + UnlockSidCacheLock(cache->keyCacheLock); + if (wrappedAesKey.data) + SECITEM_FreeItem(&wrappedAesKey, PR_FALSE); + if (wrappedMacKey.data) + SECITEM_FreeItem(&wrappedMacKey, PR_FALSE); + + if (rv != SECSuccess) { + if (aesKeyTmp) { + PK11_FreeSymKey(aesKeyTmp); + aesKeyTmp = NULL; + } + if (macKeyTmp) { + PK11_FreeSymKey(macKeyTmp); + aesKeyTmp = NULL; + } + return PR_FALSE; + } else { + return PR_TRUE; + } +} + /* The caller passes in the new value it wants * to set. This code tests the wrapped sym key entry in the shared memory. * If it is uninitialized, this function writes the caller's value into diff --git a/security/nss/lib/ssl/sslsock.c b/security/nss/lib/ssl/sslsock.c index 4354eece6..cbd735606 100644 --- a/security/nss/lib/ssl/sslsock.c +++ b/security/nss/lib/ssl/sslsock.c @@ -700,7 +700,7 @@ SSL_OptionSet(PRFileDesc *fd, PRInt32 which, PRBool on) } break; - case SSL_ENABLE_SESSION_TICKET_EXTENSION: + case SSL_ENABLE_SESSION_TICKETS: ss->opt.enableSessionTicketExtension = on; break; @@ -759,7 +759,7 @@ SSL_OptionGet(PRFileDesc *fd, PRInt32 which, PRBool *pOn) case SSL_NO_STEP_DOWN: on = ss->opt.noStepDown; break; case SSL_BYPASS_PKCS11: on = ss->opt.bypassPKCS11; break; case SSL_NO_LOCKS: on = ss->opt.noLocks; break; - case SSL_ENABLE_SESSION_TICKET_EXTENSION: + case SSL_ENABLE_SESSION_TICKETS: on = ss->opt.enableSessionTicketExtension; break; default: @@ -802,7 +802,7 @@ SSL_OptionGetDefault(PRInt32 which, PRBool *pOn) case SSL_NO_STEP_DOWN: on = ssl_defaults.noStepDown; break; case SSL_BYPASS_PKCS11: on = ssl_defaults.bypassPKCS11; break; case SSL_NO_LOCKS: on = ssl_defaults.noLocks; break; - case SSL_ENABLE_SESSION_TICKET_EXTENSION: + case SSL_ENABLE_SESSION_TICKETS: on = ssl_defaults.enableSessionTicketExtension; break; @@ -932,7 +932,7 @@ SSL_OptionSetDefault(PRInt32 which, PRBool on) } break; - case SSL_ENABLE_SESSION_TICKET_EXTENSION: + case SSL_ENABLE_SESSION_TICKETS: ssl_defaults.enableSessionTicketExtension = on; break; -- cgit v1.2.1