diff options
Diffstat (limited to 'net/third_party/nss/ssl')
| -rw-r--r-- | net/third_party/nss/ssl/snapstart.c | 7 | ||||
| -rw-r--r-- | net/third_party/nss/ssl/ssl.def | 1 | ||||
| -rw-r--r-- | net/third_party/nss/ssl/ssl.h | 40 | ||||
| -rw-r--r-- | net/third_party/nss/ssl/ssl3con.c | 117 | ||||
| -rw-r--r-- | net/third_party/nss/ssl/ssl3ext.c | 2 | ||||
| -rw-r--r-- | net/third_party/nss/ssl/sslauth.c | 58 | ||||
| -rw-r--r-- | net/third_party/nss/ssl/sslimpl.h | 80 | ||||
| -rw-r--r-- | net/third_party/nss/ssl/sslnonce.c | 5 | ||||
| -rw-r--r-- | net/third_party/nss/ssl/sslplatf.c | 561 | ||||
| -rw-r--r-- | net/third_party/nss/ssl/sslsnce.c | 5 | ||||
| -rw-r--r-- | net/third_party/nss/ssl/sslsock.c | 14 |
11 files changed, 871 insertions, 19 deletions
diff --git a/net/third_party/nss/ssl/snapstart.c b/net/third_party/nss/ssl/snapstart.c index ca2cafa..92406a7 100644 --- a/net/third_party/nss/ssl/snapstart.c +++ b/net/third_party/nss/ssl/snapstart.c @@ -48,10 +48,6 @@ /* TODO(agl): Add support for snap starting with compression. */ -/* TODO(agl): Free snapStartApplicationData as soon as the handshake has -** completed. -*/ - #include "pk11pub.h" #include "ssl.h" #include "sslimpl.h" @@ -821,6 +817,7 @@ ssl3_SendSnapStartXtn(sslSocket *ss, PRBool append, PRUint32 maxBytes) rv = ssl3_AppendSnapStartApplicationData( ss, ss->ssl3.snapStartApplicationData.data, ss->ssl3.snapStartApplicationData.len); + SECITEM_FreeItem(&ss->ssl3.snapStartApplicationData, PR_FALSE); if (rv != SECSuccess) goto loser; } @@ -1056,6 +1053,8 @@ ssl3_ResetForSnapStartRecovery(sslSocket *ss, SSL3Opaque *b, PRUint32 length) ss->ssl3.hs.snapStartType = snap_start_resume_recovery; } + ss->ssl3.nextProtoState = SSL_NEXT_PROTO_NO_SUPPORT; + ssl3_DestroyCipherSpec(ss->ssl3.pwSpec, PR_TRUE/*freeSrvName*/); return SECSuccess; diff --git a/net/third_party/nss/ssl/ssl.def b/net/third_party/nss/ssl/ssl.def index effc35d..60ebbb1 100644 --- a/net/third_party/nss/ssl/ssl.def +++ b/net/third_party/nss/ssl/ssl.def @@ -163,6 +163,7 @@ SSL_SetNextProtoNego; ;+ global: SSL_GetPredictedServerHelloData; SSL_GetSnapStartResult; +SSL_PeerCertificateChain; SSL_SetPredictedPeerCertificates; SSL_SetPredictedServerHelloData; SSL_SetSnapStartApplicationData; diff --git a/net/third_party/nss/ssl/ssl.h b/net/third_party/nss/ssl/ssl.h index 8217d2e..9d3da0c 100644 --- a/net/third_party/nss/ssl/ssl.h +++ b/net/third_party/nss/ssl/ssl.h @@ -273,6 +273,17 @@ SSL_IMPORT SECStatus SSL_SecurityStatus(PRFileDesc *fd, int *on, char **cipher, SSL_IMPORT CERTCertificate *SSL_PeerCertificate(PRFileDesc *fd); /* +** Return references to the certificates presented by the SSL peer. On entry, +** |*certs_size| must contain the size of the |certs| array. On successful +** return, |*certs_size| contains the number of certificates available and +** |certs| will contain references to as many certificates as would fit. +** Therefore if, on exit, |*certs_size| contains a value less than, or equal to, +** the entry value then all certificates were returned. +*/ +SSL_IMPORT SECStatus SSL_PeerCertificateChain( + PRFileDesc *fd, CERTCertificate **certs, unsigned int *certs_size); + +/* ** Authenticate certificate hook. Called when a certificate comes in ** (because of SSL_REQUIRE_CERTIFICATE in SSL_Enable) to authenticate the ** certificate. @@ -312,6 +323,35 @@ typedef SECStatus (PR_CALLBACK *SSLGetClientAuthData)(void *arg, SSL_IMPORT SECStatus SSL_GetClientAuthDataHook(PRFileDesc *fd, SSLGetClientAuthData f, void *a); +/* + * Prototype for SSL callback to get client auth data from the application, + * when using the underlying platform's cryptographic primitives. Returning + * SECFailure will cause the socket to send no client certificate. + * arg - application passed argument + * caNames - pointer to distinguished names of CAs that the server likes + * pRetCerts - pointer to pointer to list of certs, with the first being + * the client cert, and any following being used for chain + * building + * pRetKey - pointer to native key pointer, for return of key + * - Windows: pointer to HCRYPTPROV + * - Mac OS X: pointer to SecKeyRef + */ +typedef SECStatus (PR_CALLBACK *SSLGetPlatformClientAuthData)(void *arg, + PRFileDesc *fd, + CERTDistNames *caNames, + CERTCertList **pRetCerts,/*return */ + void **pRetKey);/* return */ + +/* + * Set the client side callback for SSL to retrieve user's private key + * and certificate. + * fd - the file descriptor for the connection in question + * f - the application's callback that delivers the key and cert + * a - application specific data + */ +SSL_IMPORT SECStatus +SSL_GetPlatformClientAuthDataHook(PRFileDesc *fd, + SSLGetPlatformClientAuthData f, void *a); /* ** SNI extension processing callback function. diff --git a/net/third_party/nss/ssl/ssl3con.c b/net/third_party/nss/ssl/ssl3con.c index 1a6612f..d3d2727 100644 --- a/net/third_party/nss/ssl/ssl3con.c +++ b/net/third_party/nss/ssl/ssl3con.c @@ -2011,6 +2011,12 @@ ssl3_ComputeRecordMAC( static PRBool ssl3_ClientAuthTokenPresent(sslSessionID *sid) { +#ifdef NSS_PLATFORM_CLIENT_AUTH + if (!sid || !sid->u.ssl3.clPlatformAuthValid) { + return PR_TRUE; + } + return ssl_PlatformAuthTokenPresent(&sid->u.ssl3.clPlatformAuthInfo); +#else PK11SlotInfo *slot = NULL; PRBool isPresent = PR_TRUE; @@ -2034,6 +2040,7 @@ ssl3_ClientAuthTokenPresent(sslSessionID *sid) { PK11_FreeSlot(slot); } return isPresent; +#endif /* NSS_PLATFORM_CLIENT_AUTH */ } SECStatus @@ -4827,6 +4834,20 @@ ssl3_SendCertificateVerify(sslSocket *ss) } isTLS = (PRBool)(ss->ssl3.pwSpec->version > SSL_LIBRARY_VERSION_3_0); +#ifdef NSS_PLATFORM_CLIENT_AUTH + rv = ssl3_PlatformSignHashes(&hashes, ss->ssl3.platformClientKey, + &buf, isTLS); + if (rv == SECSuccess) { + sslSessionID * sid = ss->sec.ci.sid; + ssl_GetPlatformAuthInfoForKey(ss->ssl3.platformClientKey, + &sid->u.ssl3.clPlatformAuthInfo); + sid->u.ssl3.clPlatformAuthValid = PR_TRUE; + } + if (ss->ssl3.hs.kea_def->exchKeyType == kt_rsa) { + ssl_FreePlatformKey(ss->ssl3.platformClientKey); + ss->ssl3.platformClientKey = (PlatformKey)NULL; + } +#else /* NSS_PLATFORM_CLIENT_AUTH */ rv = ssl3_SignHashes(&hashes, ss->ssl3.clientPrivateKey, &buf, isTLS); if (rv == SECSuccess) { PK11SlotInfo * slot; @@ -4851,6 +4872,7 @@ ssl3_SendCertificateVerify(sslSocket *ss) SECKEY_DestroyPrivateKey(ss->ssl3.clientPrivateKey); ss->ssl3.clientPrivateKey = NULL; } +#endif /* NSS_PLATFORM_CLIENT_AUTH */ if (rv != SECSuccess) { goto done; /* err code was set by ssl3_SignHashes */ } @@ -5481,6 +5503,10 @@ ssl3_HandleCertificateRequest(sslSocket *ss, SSL3Opaque *b, PRUint32 length) SSL3AlertDescription desc = illegal_parameter; SECItem cert_types = {siBuffer, NULL, 0}; CERTDistNames ca_list; +#ifdef NSS_PLATFORM_CLIENT_AUTH + CERTCertList * platform_cert_list = NULL; + CERTCertListNode * certNode = NULL; +#endif /* NSS_PLATFORM_CLIENT_AUTH */ SSL_TRC(3, ("%d: SSL3[%d]: handle certificate_request handshake", SSL_GETPID(), ss->fd)); @@ -5507,6 +5533,12 @@ ssl3_HandleCertificateRequest(sslSocket *ss, SSL3Opaque *b, PRUint32 length) SECKEY_DestroyPrivateKey(ss->ssl3.clientPrivateKey); ss->ssl3.clientPrivateKey = NULL; } +#ifdef NSS_PLATFORM_CLIENT_AUTH + if (ss->ssl3.platformClientKey) { + ssl_FreePlatformKey(ss->ssl3.platformClientKey); + ss->ssl3.platformClientKey = (PlatformKey)NULL; + } +#endif /* NSS_PLATFORM_CLIENT_AUTH */ isTLS = (PRBool)(ss->ssl3.prSpec->version > SSL_LIBRARY_VERSION_3_0); rv = ssl3_ConsumeHandshakeVariable(ss, &cert_types, 1, &b, &length); @@ -5573,6 +5605,18 @@ ssl3_HandleCertificateRequest(sslSocket *ss, SSL3Opaque *b, PRUint32 length) desc = no_certificate; ss->ssl3.hs.ws = wait_hello_done; +#ifdef NSS_PLATFORM_CLIENT_AUTH + if (ss->getPlatformClientAuthData == NULL) { + rv = SECFailure; /* force it to send a no_certificate alert */ + } else { + /* XXX Should pass cert_types in this call!! */ + rv = (SECStatus)(*ss->getPlatformClientAuthData)( + ss->getPlatformClientAuthDataArg, + ss->fd, &ca_list, + &platform_cert_list, + (void**)&ss->ssl3.platformClientKey); + } +#else if (ss->getClientAuthData == NULL) { rv = SECFailure; /* force it to send a no_certificate alert */ } else { @@ -5582,12 +5626,51 @@ ssl3_HandleCertificateRequest(sslSocket *ss, SSL3Opaque *b, PRUint32 length) &ss->ssl3.clientCertificate, &ss->ssl3.clientPrivateKey); } +#endif /* NSS_PLATFORM_CLIENT_AUTH */ switch (rv) { case SECWouldBlock: /* getClientAuthData has put up a dialog box. */ ssl_SetAlwaysBlock(ss); break; /* not an error */ case SECSuccess: +#ifdef NSS_PLATFORM_CLIENT_AUTH + if (!platform_cert_list || CERT_LIST_EMPTY(platform_cert_list) || + !ss->ssl3.platformClientKey) { + if (platform_cert_list) { + CERT_DestroyCertList(platform_cert_list); + platform_cert_list = NULL; + } + if (ss->ssl3.platformClientKey) { + ssl_FreePlatformKey(ss->ssl3.platformClientKey); + ss->ssl3.platformClientKey = (PlatformKey)NULL; + } + goto send_no_certificate; + } + + certNode = CERT_LIST_HEAD(platform_cert_list); + ss->ssl3.clientCertificate = CERT_DupCertificate(certNode->cert); + + /* Setting ssl3.clientCertChain non-NULL will cause + * ssl3_HandleServerHelloDone to call SendCertificate. + * Note: clientCertChain should include the EE cert as + * clientCertificate is ignored during the actual sending + */ + ss->ssl3.clientCertChain = + hack_NewCertificateListFromCertList(platform_cert_list); + CERT_DestroyCertList(platform_cert_list); + platform_cert_list = NULL; + if (ss->ssl3.clientCertChain == NULL) { + if (ss->ssl3.clientCertificate != NULL) { + CERT_DestroyCertificate(ss->ssl3.clientCertificate); + ss->ssl3.clientCertificate = NULL; + } + if (ss->ssl3.platformClientKey) { + ssl_FreePlatformKey(ss->ssl3.platformClientKey); + ss->ssl3.platformClientKey = (PlatformKey)NULL; + } + goto send_no_certificate; + } +#else /* check what the callback function returned */ if ((!ss->ssl3.clientCertificate) || (!ss->ssl3.clientPrivateKey)) { /* we are missing either the key or cert */ @@ -5620,6 +5703,7 @@ ssl3_HandleCertificateRequest(sslSocket *ss, SSL3Opaque *b, PRUint32 length) } goto send_no_certificate; } +#endif /* NSS_PLATFORM_CLIENT_AUTH */ break; /* not an error */ case SECFailure: @@ -5650,6 +5734,10 @@ loser: done: if (arena != NULL) PORT_FreeArena(arena, PR_FALSE); +#ifdef NSS_PLATFORM_CLIENT_AUTH + if (platform_cert_list) + CERT_DestroyCertList(platform_cert_list); +#endif return rv; } @@ -5758,6 +5846,16 @@ ssl3_HandleServerHelloDone(sslSocket *ss) goto loser; /* error code is set. */ } } else +#ifdef NSS_PLATFORM_CLIENT_AUTH + if (ss->ssl3.clientCertChain != NULL && + ss->ssl3.platformClientKey) { + send_verify = PR_TRUE; + rv = ssl3_SendCertificate(ss); + if (rv != SECSuccess) { + goto loser; /* error code is set. */ + } + } +#else if (ss->ssl3.clientCertChain != NULL && ss->ssl3.clientPrivateKey != NULL) { send_verify = PR_TRUE; @@ -5766,6 +5864,7 @@ ssl3_HandleServerHelloDone(sslSocket *ss) goto loser; /* error code is set. */ } } +#endif /* NSS_PLATFORM_CLIENT_AUTH */ rv = ssl3_SendClientKeyExchange(ss); if (rv != SECSuccess) { @@ -8366,20 +8465,6 @@ ssl3_SendFinished(sslSocket *ss, PRInt32 flags) } } - if ((ss->ssl3.hs.snapStartType == snap_start_recovery || - ss->ssl3.hs.snapStartType == snap_start_resume_recovery) && - ss->ssl3.snapStartApplicationData.data) { - /* In the event that the server ignored the application data in our - * snap start extension, we need to retransmit it now. */ - PRInt32 sent = ssl3_SendRecord(ss, content_application_data, - ss->ssl3.snapStartApplicationData.data, - ss->ssl3.snapStartApplicationData.len, - flags); - SECITEM_FreeItem(&ss->ssl3.snapStartApplicationData, PR_FALSE); - if (sent < 0) - return (SECStatus)sent; /* error code set by ssl3_SendRecord */ - } - return SECSuccess; fail: @@ -9640,6 +9725,10 @@ ssl3_DestroySSL3Info(sslSocket *ss) if (ss->ssl3.clientPrivateKey != NULL) SECKEY_DestroyPrivateKey(ss->ssl3.clientPrivateKey); +#ifdef NSS_PLATFORM_CLIENT_AUTH + if (ss->ssl3.platformClientKey) + ssl_FreePlatformKey(ss->ssl3.platformClientKey); +#endif /* NSS_PLATFORM_CLIENT_AUTH */ if (ss->ssl3.peerCertArena != NULL) ssl3_CleanupPeerCerts(ss); diff --git a/net/third_party/nss/ssl/ssl3ext.c b/net/third_party/nss/ssl/ssl3ext.c index a7ae062..f044e1c 100644 --- a/net/third_party/nss/ssl/ssl3ext.c +++ b/net/third_party/nss/ssl/ssl3ext.c @@ -46,8 +46,8 @@ #include "nssrenam.h" #include "nss.h" #include "ssl.h" -#include "sslproto.h" #include "sslimpl.h" +#include "sslproto.h" #include "pk11pub.h" #include "blapi.h" #include "prinit.h" diff --git a/net/third_party/nss/ssl/sslauth.c b/net/third_party/nss/ssl/sslauth.c index 39c630d..3f4924d 100644 --- a/net/third_party/nss/ssl/sslauth.c +++ b/net/third_party/nss/ssl/sslauth.c @@ -60,6 +60,42 @@ SSL_PeerCertificate(PRFileDesc *fd) } /* NEED LOCKS IN HERE. */ +SECStatus +SSL_PeerCertificateChain(PRFileDesc *fd, CERTCertificate **certs, + unsigned int *certsSize) +{ + sslSocket *ss; + unsigned int inSize = *certsSize; + ssl3CertNode* cur; + + ss = ssl_FindSocket(fd); + if (!ss) { + SSL_DBG(("%d: SSL[%d]: bad socket in PeerCertificateChain", + SSL_GETPID(), fd)); + return SECFailure; + } + if (!ss->opt.useSecurity) + return SECFailure; + + if (ss->sec.peerCert == NULL) { + *certsSize = 0; + return SECSuccess; + } + + *certsSize = 1; /* for the leaf certificate */ + if (inSize > 0) + certs[0] = CERT_DupCertificate(ss->sec.peerCert); + + for (cur = ss->ssl3.peerCertChain; cur; cur = cur->next) { + if (*certsSize < inSize) + certs[*certsSize] = CERT_DupCertificate(cur->cert); + (*certsSize)++; + } + + return SECSuccess; +} + +/* NEED LOCKS IN HERE. */ CERTCertificate * SSL_LocalCertificate(PRFileDesc *fd) { @@ -216,6 +252,28 @@ SSL_GetClientAuthDataHook(PRFileDesc *s, SSLGetClientAuthData func, return SECSuccess; } +#ifdef NSS_PLATFORM_CLIENT_AUTH +/* NEED LOCKS IN HERE. */ +SECStatus +SSL_GetPlatformClientAuthDataHook(PRFileDesc *s, + SSLGetPlatformClientAuthData func, + void *arg) +{ + sslSocket *ss; + + ss = ssl_FindSocket(s); + if (!ss) { + SSL_DBG(("%d: SSL[%d]: bad socket in GetPlatformClientAuthDataHook", + SSL_GETPID(), s)); + return SECFailure; + } + + ss->getPlatformClientAuthData = func; + ss->getPlatformClientAuthDataArg = arg; + return SECSuccess; +} +#endif /* NSS_PLATFORM_CLIENT_AUTH */ + /* NEED LOCKS IN HERE. */ SECStatus SSL_SetPKCS11PinArg(PRFileDesc *s, void *arg) diff --git a/net/third_party/nss/ssl/sslimpl.h b/net/third_party/nss/ssl/sslimpl.h index f708696..b84511b 100644 --- a/net/third_party/nss/ssl/sslimpl.h +++ b/net/third_party/nss/ssl/sslimpl.h @@ -65,6 +65,15 @@ #include "sslt.h" /* for some formerly private types, now public */ +#ifdef NSS_PLATFORM_CLIENT_AUTH +#if defined(XP_WIN32) +#include <windows.h> +#include <wincrypt.h> +#elif defined(XP_MACOSX) +#include <Security/Security.h> +#endif +#endif + /* to make some of these old enums public without namespace pollution, ** it was necessary to prepend ssl_ to the names. ** These #defines preserve compatibility with the old code here in libssl. @@ -573,6 +582,19 @@ typedef enum { never_cached, #define MAX_PEER_CERT_CHAIN_SIZE 8 +#ifdef NSS_PLATFORM_CLIENT_AUTH +typedef struct { +#if defined(XP_WIN32) + char * provider; + char * container; + DWORD provType; +#elif defined(XP_MACOSX) + SecKeychainRef keychain; + CFDataRef persistentKey; +#endif +} PlatformAuthInfo; +#endif /* NSS_PLATFORM_CLIENT_AUTH */ + struct sslSessionIDStr { sslSessionID * next; /* chain used for client sockets, only */ @@ -657,6 +679,11 @@ struct sslSessionIDStr { char masterValid; char clAuthValid; +#ifdef NSS_PLATFORM_CLIENT_AUTH + PlatformAuthInfo clPlatformAuthInfo; + char clPlatformAuthValid; +#endif /* NSS_PLATFORM_CLIENT_AUTH */ + /* Session ticket if we have one, is sent as an extension in the * ClientHello message. This field is used by clients. */ @@ -816,6 +843,15 @@ const ssl3CipherSuiteDef *suite_def; PRBool nextProtoNego;/* Our peer has sent this extension */ } SSL3HandshakeState; +#ifdef NSS_PLATFORM_CLIENT_AUTH +#if defined(XP_WIN32) +typedef HCRYPTPROV PlatformKey; +#elif defined(XP_MACOSX) +typedef SecKeyRef PlatformKey; +#else +typedef void *PlatformKey; +#endif +#endif /* @@ -839,6 +875,9 @@ struct ssl3StateStr { CERTCertificate * clientCertificate; /* used by client */ SECKEYPrivateKey * clientPrivateKey; /* used by client */ +#ifdef NSS_PLATFORM_CLIENT_AUTH + PlatformKey platformClientKey; /* used by client */ +#endif /* NSS_PLATFORM_CLIENT_AUTH */ CERTCertificateList *clientCertChain; /* used by client */ PRBool sendEmptyCert; /* used by client */ @@ -1100,6 +1139,10 @@ const unsigned char * preferredCipher; void *authCertificateArg; SSLGetClientAuthData getClientAuthData; void *getClientAuthDataArg; +#ifdef NSS_PLATFORM_CLIENT_AUTH + SSLGetPlatformClientAuthData getPlatformClientAuthData; + void *getPlatformClientAuthDataArg; +#endif /* NSS_PLATFORM_CLIENT_AUTH */ SSLSNISocketConfig sniSocketConfig; void *sniSocketConfigArg; SSLBadCertHandler handleBadCert; @@ -1691,6 +1734,43 @@ extern SECStatus ssl_InitSessionCacheLocks(PRBool lazyInit); extern SECStatus ssl_FreeSessionCacheLocks(void); +/***************** platform client auth ****************/ + +#ifdef NSS_PLATFORM_CLIENT_AUTH +// Releases the platform key. +extern void ssl_FreePlatformKey(PlatformKey key); + +// Frees any memory allocated to store a persistent reference to the +// platform key. +extern void ssl_FreePlatformAuthInfo(PlatformAuthInfo* info); + +// Initializes the PlatformAuthInfo to empty/invalid values. +extern void ssl_InitPlatformAuthInfo(PlatformAuthInfo* info); + +// Determine if the given key is still present in the system. This is used +// to check for things like smart cards being ejected after handshaking, +// since no further operations on the key will happen which would detect this. +extern PRBool ssl_PlatformAuthTokenPresent(PlatformAuthInfo* info); + +// Obtain a persistent reference to a key, sufficient for +// ssl_PlatformAuthTokenPresent to determine if the key is still present. +extern void ssl_GetPlatformAuthInfoForKey(PlatformKey key, + PlatformAuthInfo* info); + +// Implement the client CertificateVerify message for SSL3/TLS1.0 +extern SECStatus ssl3_PlatformSignHashes(SSL3Hashes *hash, + PlatformKey key, SECItem *buf, + PRBool isTLS); + +// Converts a CERTCertList* (A collection of CERTCertificates) into a +// CERTCertificateList* (A collection of SECItems), or returns NULL if +// it cannot be converted. +// This is to allow the platform-supplied chain to be created with purely +// public API functions, using the preferred CERTCertList mutators, rather +// pushing this hack to clients. +extern CERTCertificateList* hack_NewCertificateListFromCertList( + CERTCertList* list); +#endif /* NSS_PLATFORM_CLIENT_AUTH */ /********************** misc calls *********************/ diff --git a/net/third_party/nss/ssl/sslnonce.c b/net/third_party/nss/ssl/sslnonce.c index 64adc1f..345f041 100644 --- a/net/third_party/nss/ssl/sslnonce.c +++ b/net/third_party/nss/ssl/sslnonce.c @@ -226,6 +226,11 @@ ssl_DestroySID(sslSessionID *sid) if (sid->u.ssl3.sessionTicket.ticket.data) { SECITEM_FreeItem(&sid->u.ssl3.sessionTicket.ticket, PR_FALSE); } +#ifdef NSS_PLATFORM_CLIENT_AUTH + if (sid->u.ssl3.clPlatformAuthValid) { + ssl_FreePlatformAuthInfo(&sid->u.ssl3.clPlatformAuthInfo); + } +#endif /* NSS_PLATFORM_CLIENT_AUTH */ PORT_ZFree(sid, sizeof(sslSessionID)); } diff --git a/net/third_party/nss/ssl/sslplatf.c b/net/third_party/nss/ssl/sslplatf.c new file mode 100644 index 0000000..7119543 --- /dev/null +++ b/net/third_party/nss/ssl/sslplatf.c @@ -0,0 +1,561 @@ +/* + * Platform specific crypto wrappers + * + * ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Netscape security libraries. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1994-2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Ryan Sleevi <ryan.sleevi@gmail.com> + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ +/* $Id$ */ +#include "ssl.h" +#include "certt.h" +#include "keythi.h" +#include "sslimpl.h" +#include "cryptohi.h" +#include "secitem.h" + +#ifdef NSS_PLATFORM_CLIENT_AUTH +CERTCertificateList* +hack_NewCertificateListFromCertList(CERTCertList* list) +{ + CERTCertificateList * chain = NULL; + PRArenaPool * arena = NULL; + CERTCertListNode * node; + int len; + + if (CERT_LIST_EMPTY(list)) + goto loser; + + arena = PORT_NewArena(4096); + if (arena == NULL) + goto loser; + + for (len = 0, node = CERT_LIST_HEAD(list); !CERT_LIST_END(node, list); + len++, node = CERT_LIST_NEXT(node)) { + } + + chain = PORT_ArenaNew(arena, CERTCertificateList); + if (chain == NULL) + goto loser; + + chain->certs = PORT_ArenaNewArray(arena, SECItem, len); + if (!chain->certs) + goto loser; + chain->len = len; + + for (len = 0, node = CERT_LIST_HEAD(list); !CERT_LIST_END(node, list); + len++, node = CERT_LIST_NEXT(node)) { + // Check to see if the last cert to be sent is a self-signed cert, + // and if so, omit it from the list of certificates. However, if + // there is only one cert (len == 0), include the cert, as it means + // the EE cert is self-signed. + if (len > 0 && (len == chain->len - 1) && node->cert->isRoot) { + chain->len = len; + break; + } + SECITEM_CopyItem(arena, &chain->certs[len], &node->cert->derCert); + } + + chain->arena = arena; + return chain; + +loser: + if (arena) { + PORT_FreeArena(arena, PR_FALSE); + } + return NULL; +} + +#if defined(XP_WIN32) +void +ssl_FreePlatformKey(PlatformKey key) +{ + CryptReleaseContext(key, 0); +} + +void +ssl_FreePlatformAuthInfo(PlatformAuthInfo* info) +{ + if (info->provider != NULL) { + PORT_Free(info->provider); + info->provider = NULL; + } + if (info->container != NULL) { + PORT_Free(info->container); + info->container = NULL; + } + info->provType = 0; +} + +void +ssl_InitPlatformAuthInfo(PlatformAuthInfo* info) +{ + info->provider = NULL; + info->container = NULL; + info->provType = 0; +} + +PRBool +ssl_PlatformAuthTokenPresent(PlatformAuthInfo *info) +{ + HCRYPTPROV prov = 0; + + if (!info || !info->provider || !info->container) + return PR_FALSE; + + if (!CryptAcquireContextA(&prov, info->container, info->provider, + info->provType, 0)) + return PR_FALSE; + + CryptReleaseContext(prov, 0); + return PR_TRUE; +} + +void +ssl_GetPlatformAuthInfoForKey(PlatformKey key, + PlatformAuthInfo *info) +{ + DWORD bytesNeeded = 0; + ssl_InitPlatformAuthInfo(info); + bytesNeeded = sizeof(info->provType); + if (!CryptGetProvParam(key, PP_PROVTYPE, (BYTE*)&info->provType, + &bytesNeeded, 0)) + goto error; + + bytesNeeded = 0; + if (!CryptGetProvParam(key, PP_CONTAINER, NULL, &bytesNeeded, 0)) + goto error; + info->container = (char*)PORT_Alloc(bytesNeeded); + if (info->container == NULL) + goto error; + if (!CryptGetProvParam(key, PP_CONTAINER, (BYTE*)info->container, + &bytesNeeded, 0)) + goto error; + + bytesNeeded = 0; + if (!CryptGetProvParam(key, PP_NAME, NULL, &bytesNeeded, 0)) + goto error; + info->provider = (char*)PORT_Alloc(bytesNeeded); + if (info->provider == NULL) + goto error; + if (!CryptGetProvParam(key, PP_NAME, (BYTE*)info->provider, + &bytesNeeded, 0)) + goto error; + + goto done; +error: + ssl_FreePlatformAuthInfo(info); + +done: + return; +} + +SECStatus +ssl3_PlatformSignHashes(SSL3Hashes *hash, PlatformKey key, SECItem *buf, + PRBool isTLS) +{ + SECStatus rv = SECFailure; + PRBool doDerEncode = PR_FALSE; + SECItem hashItem; + /* TODO(rsleevi): Should AT_SIGNATURE also be checked if doing client + * auth? + */ + DWORD keySpec = AT_KEYEXCHANGE; + HCRYPTKEY hKey = 0; + DWORD argLen = 0; + ALG_ID keyAlg = 0; + DWORD signatureLen = 0; + ALG_ID hashAlg = 0; + HCRYPTHASH hHash = 0; + DWORD hashLen = 0; + unsigned int i = 0; + + buf->data = NULL; + if (!CryptGetUserKey(key, keySpec, &hKey)) { + PORT_SetError(SEC_ERROR_INVALID_KEY); + goto done; + } + + argLen = sizeof(keyAlg); + if (!CryptGetKeyParam(hKey, KP_ALGID, (BYTE*)&keyAlg, &argLen, 0)) { + PORT_SetError(SEC_ERROR_INVALID_KEY); + goto done; + } + + switch (keyAlg) { + case CALG_RSA_KEYX: + case CALG_RSA_SIGN: + hashAlg = CALG_SSL3_SHAMD5; + hashItem.data = hash->md5; + hashItem.len = sizeof(SSL3Hashes); + break; + case CALG_DSS_SIGN: + /* TODO: Support CALG_ECDSA once tested */ + case CALG_ECDSA: + if (keyAlg == CALG_ECDSA) { + doDerEncode = PR_TRUE; + } else { + doDerEncode = isTLS; + } + hashAlg = CALG_SHA1; + hashItem.data = hash->sha; + hashItem.len = sizeof(hash->sha); + break; + default: + PORT_SetError(SEC_ERROR_UNSUPPORTED_KEYALG); + goto done; + } + PRINT_BUF(60, (NULL, "hash(es) to be signed", hashItem.data, hashItem.len)); + + if (!CryptCreateHash(key, hashAlg, 0, 0, &hHash)) { + ssl_MapLowLevelError(SSL_ERROR_SIGN_HASHES_FAILURE); + goto done; + } + argLen = sizeof(hashLen); + if (!CryptGetHashParam(hHash, HP_HASHSIZE, (BYTE*)&hashLen, &argLen, 0)) { + ssl_MapLowLevelError(SSL_ERROR_SIGN_HASHES_FAILURE); + goto done; + } + if (hashLen != hashItem.len) { + ssl_MapLowLevelError(SSL_ERROR_SIGN_HASHES_FAILURE); + goto done; + } + if (!CryptSetHashParam(hHash, HP_HASHVAL, (BYTE*)hashItem.data, 0)) { + ssl_MapLowLevelError(SSL_ERROR_SIGN_HASHES_FAILURE); + goto done; + } + if (!CryptSignHash(hHash, keySpec, NULL, CRYPT_NOHASHOID, + NULL, &signatureLen) || signatureLen == 0) { + ssl_MapLowLevelError(SSL_ERROR_SIGN_HASHES_FAILURE); + goto done; + } + buf->len = signatureLen; + buf->data = (unsigned char *)PORT_Alloc(signatureLen); + if (!buf->data) + goto done; /* error code was set. */ + + if (!CryptSignHash(hHash, keySpec, NULL, CRYPT_NOHASHOID, + (BYTE*)buf->data, &signatureLen)) { + ssl_MapLowLevelError(SSL_ERROR_SIGN_HASHES_FAILURE); + goto done; + } + + /* CryptoAPI signs in little-endian, so reverse */ + for (i = 0; i < buf->len / 2; ++i) { + unsigned char tmp = buf->data[i]; + buf->data[i] = buf->data[buf->len - 1 - i]; + buf->data[buf->len - 1 - i] = tmp; + } + if (doDerEncode) { + SECItem derSig = {siBuffer, NULL, 0}; + + /* This also works for an ECDSA signature */ + rv = DSAU_EncodeDerSigWithLen(&derSig, buf, buf->len); + if (rv == SECSuccess) { + PORT_Free(buf->data); /* discard unencoded signature. */ + *buf = derSig; /* give caller encoded signature. */ + } else if (derSig.data) { + PORT_Free(derSig.data); + } + } + + PRINT_BUF(60, (NULL, "signed hashes", buf->data, buf->len)); + rv = SECSuccess; +done: + if (hHash) + CryptDestroyHash(hHash); + if (hKey) + CryptDestroyKey(hKey); + if (rv != SECSuccess && buf->data) { + PORT_Free(buf->data); + buf->data = NULL; + } + return rv; +} + +#elif defined(XP_MACOSX) +#include <Security/cssm.h> + +/* + * In Mac OS X 10.5, these two functions are private but implemented, and + * in Mac OS X 10.6, these are exposed publicly. To compile with the 10.5 + * SDK, we declare them here. + */ +OSStatus SecKeychainItemCreatePersistentReference(SecKeychainItemRef itemRef, CFDataRef *persistentItemRef); +OSStatus SecKeychainItemCopyFromPersistentReference(CFDataRef persistentItemRef, SecKeychainItemRef *itemRef); + +void +ssl_FreePlatformKey(PlatformKey key) +{ + CFRelease(key); +} + +void +ssl_FreePlatformAuthInfo(PlatformAuthInfo* info) +{ + if (info->keychain != NULL) { + CFRelease(info->keychain); + info->keychain = NULL; + } + if (info->persistentKey != NULL) { + CFRelease(info->persistentKey); + info->persistentKey = NULL; + } +} + +void +ssl_InitPlatformAuthInfo(PlatformAuthInfo* info) +{ + info->keychain = NULL; + info->persistentKey = NULL; +} + +PRBool +ssl_PlatformAuthTokenPresent(PlatformAuthInfo* info) +{ + if (!info || !info->keychain || !info->persistentKey) + return PR_FALSE; + + // Not actually interested in the status, but it can be used to make sure + // that the keychain still exists (as smart card ejection will remove + // the keychain) + SecKeychainStatus keychainStatus; + OSStatus rv = SecKeychainGetStatus(info->keychain, &keychainStatus); + if (rv != noErr) + return PR_FALSE; + + // Make sure the individual key still exists within the keychain, if + // the keychain is present + SecKeychainItemRef keychainItem; + rv = SecKeychainItemCopyFromPersistentReference(info->persistentKey, + &keychainItem); + if (rv != noErr) + return PR_FALSE; + + CFRelease(keychainItem); + return PR_TRUE; +} + +void +ssl_GetPlatformAuthInfoForKey(PlatformKey key, + PlatformAuthInfo *info) +{ + SecKeychainItemRef keychainItem = (SecKeychainItemRef)key; + OSStatus rv = SecKeychainItemCopyKeychain(keychainItem, &info->keychain); + if (rv == noErr) { + rv = SecKeychainItemCreatePersistentReference(keychainItem, + &info->persistentKey); + } + if (rv != noErr) { + ssl_FreePlatformAuthInfo(info); + } + return; +} + +SECStatus +ssl3_PlatformSignHashes(SSL3Hashes *hash, PlatformKey key, SECItem *buf, + PRBool isTLS) +{ + SECStatus rv = SECFailure; + PRBool doDerEncode = PR_FALSE; + unsigned int signatureLen; + OSStatus status = noErr; + CSSM_CSP_HANDLE cspHandle = 0; + const CSSM_KEY *cssmKey = NULL; + CSSM_ALGORITHMS sigAlg; + const CSSM_ACCESS_CREDENTIALS * cssmCreds = NULL; + CSSM_RETURN cssmRv; + CSSM_DATA hashData; + CSSM_DATA signatureData; + CSSM_CC_HANDLE cssmSignature = 0; + + buf->data = NULL; + + status = SecKeyGetCSPHandle(key, &cspHandle); + if (status != noErr) { + PORT_SetError(SEC_ERROR_INVALID_KEY); + goto done; + } + + status = SecKeyGetCSSMKey(key, &cssmKey); + if (status != noErr || !cssmKey) { + PORT_SetError(SEC_ERROR_INVALID_KEY); + goto done; + } + + /* SecKeyGetBlockSize wasn't addeded until OS X 10.6 - but the + * needed information is readily available on the key itself. + */ + signatureLen = (cssmKey->KeyHeader.LogicalKeySizeInBits + 7) / 8; + + if (signatureLen == 0) { + PORT_SetError(SEC_ERROR_INVALID_KEY); + goto done; + } + + buf->len = signatureLen; + buf->data = (unsigned char *)PORT_Alloc(signatureLen); + if (!buf->data) + goto done; /* error code was set. */ + + sigAlg = cssmKey->KeyHeader.AlgorithmId; + switch (sigAlg) { + case CSSM_ALGID_RSA: + hashData.Data = hash->md5; + hashData.Length = sizeof(SSL3Hashes); + break; + case CSSM_ALGID_ECDSA: + case CSSM_ALGID_DSA: + if (sigAlg == CSSM_ALGID_ECDSA) { + doDerEncode = PR_TRUE; + } else { + doDerEncode = isTLS; + } + hashData.Data = hash->sha; + hashData.Length = sizeof(hash->sha); + break; + default: + PORT_SetError(SEC_ERROR_INVALID_KEY); + goto done; + } + PRINT_BUF(60, (NULL, "hash(es) to be signed", hashData.Data, hashData.Length)); + + /* TODO(rsleevi): Should it be kSecCredentialTypeNoUI? In Win32, at least, + * you can prevent the UI by setting the provider handle on the + * certificate to be opened with CRYPT_SILENT, but is there an equivalent? + */ + status = SecKeyGetCredentials(key, CSSM_ACL_AUTHORIZATION_SIGN, + kSecCredentialTypeDefault, &cssmCreds); + if (status != noErr) { + ssl_MapLowLevelError(SSL_ERROR_SIGN_HASHES_FAILURE); + goto done; + } + + signatureData.Length = buf->len; + signatureData.Data = (uint8*)buf->data; + + cssmRv = CSSM_CSP_CreateSignatureContext(cspHandle, sigAlg, cssmCreds, + cssmKey, &cssmSignature); + if (cssmRv) { + ssl_MapLowLevelError(SSL_ERROR_SIGN_HASHES_FAILURE); + goto done; + } + + /* See "Apple Cryptographic Service Provider Functional Specification" */ + if (cssmKey->KeyHeader.AlgorithmId == CSSM_ALGID_RSA) { + /* To set RSA blinding for RSA keys */ + CSSM_CONTEXT_ATTRIBUTE blindingAttr; + blindingAttr.AttributeType = CSSM_ATTRIBUTE_RSA_BLINDING; + blindingAttr.AttributeLength = sizeof(uint32); + blindingAttr.Attribute.Uint32 = 1; + cssmRv = CSSM_UpdateContextAttributes(cssmSignature, 1, &blindingAttr); + if (cssmRv) { + ssl_MapLowLevelError(SSL_ERROR_SIGN_HASHES_FAILURE); + goto done; + } + } + + cssmRv = CSSM_SignData(cssmSignature, &hashData, 1, CSSM_ALGID_NONE, + &signatureData); + if (cssmRv) { + ssl_MapLowLevelError(SSL_ERROR_SIGN_HASHES_FAILURE); + goto done; + } + + if (doDerEncode) { + SECItem derSig = {siBuffer, NULL, 0}; + + /* This also works for an ECDSA signature */ + rv = DSAU_EncodeDerSigWithLen(&derSig, buf, buf->len); + if (rv == SECSuccess) { + PORT_Free(buf->data); /* discard unencoded signature. */ + *buf = derSig; /* give caller encoded signature. */ + } else if (derSig.data) { + PORT_Free(derSig.data); + } + } + + PRINT_BUF(60, (NULL, "signed hashes", buf->data, buf->len)); + rv = SECSuccess; +done: + /* cspHandle, cssmKey, and cssmCreds are owned by the SecKeyRef and + * should not be freed. When the PlatformKey is freed, they will be + * released. + */ + if (cssmSignature) + CSSM_DeleteContext(cssmSignature); + + if (rv != SECSuccess && buf->data) { + PORT_Free(buf->data); + buf->data = NULL; + } + return rv; +} +#else +void +ssl_FreePlatformKey(PlatformKey key) +{ +} + +void +ssl_FreePlatformAuthInfo(PlatformAuthInfo *info) +{ +} + +void +ssl_InitPlatformAuthInfo(PlatformAuthInfo *info) +{ +} + +PRBool +ssl_PlatformAuthTokenPresent(PlatformAuthInfo *info) +{ + return PR_FALSE; +} + +void +ssl_GetPlatformAuthInfoForKey(PlatformKey key, PlatformAuthInfo *info) +{ +} + +SECStatus +ssl3_PlatformSignHashes(SSL3Hashes *hash, PlatformKey key, SECItem *buf, + PRBool isTLS) +{ + PORT_SetError(PR_NOT_IMPLEMENTED_ERROR); + return SECFailure; +} +#endif + +#endif /* NSS_PLATFORM_CLIENT_AUTH */ diff --git a/net/third_party/nss/ssl/sslsnce.c b/net/third_party/nss/ssl/sslsnce.c index 6c73f25..4176ac8 100644 --- a/net/third_party/nss/ssl/sslsnce.c +++ b/net/third_party/nss/ssl/sslsnce.c @@ -638,6 +638,11 @@ ConvertToSID(sidCacheEntry * from, to->u.ssl3.clAuthSeries = 0; to->u.ssl3.clAuthValid = PR_FALSE; +#ifdef NSS_PLATFORM_CLIENT_AUTH + ssl_InitPlatformAuthInfo(&to->u.ssl3.clPlatformAuthInfo); + to->u.ssl3.clPlatformAuthValid = PR_FALSE; +#endif /* NSS_PLATFORM_CLIENT_AUTH */ + if (from->u.ssl3.certIndex != -1 && pcce) { SECItem derCert; diff --git a/net/third_party/nss/ssl/sslsock.c b/net/third_party/nss/ssl/sslsock.c index 2898b88..33e7f3e 100644 --- a/net/third_party/nss/ssl/sslsock.c +++ b/net/third_party/nss/ssl/sslsock.c @@ -336,6 +336,10 @@ ssl_DupSocket(sslSocket *os) ss->authCertificateArg = os->authCertificateArg; ss->getClientAuthData = os->getClientAuthData; ss->getClientAuthDataArg = os->getClientAuthDataArg; +#ifdef NSS_PLATFORM_CLIENT_AUTH + ss->getPlatformClientAuthData = os->getPlatformClientAuthData; + ss->getPlatformClientAuthDataArg = os->getPlatformClientAuthDataArg; +#endif ss->sniSocketConfig = os->sniSocketConfig; ss->sniSocketConfigArg = os->sniSocketConfigArg; ss->handleBadCert = os->handleBadCert; @@ -1443,6 +1447,12 @@ SSL_ReconfigFD(PRFileDesc *model, PRFileDesc *fd) ss->getClientAuthData = sm->getClientAuthData; if (sm->getClientAuthDataArg) ss->getClientAuthDataArg = sm->getClientAuthDataArg; +#ifdef NSS_PLATFORM_CLIENT_AUTH + if (sm->getPlatformClientAuthData) + ss->getPlatformClientAuthData = sm->getPlatformClientAuthData; + if (sm->getPlatformClientAuthDataArg) + ss->getPlatformClientAuthDataArg = sm->getPlatformClientAuthDataArg; +#endif if (sm->sniSocketConfig) ss->sniSocketConfig = sm->sniSocketConfig; if (sm->sniSocketConfigArg) @@ -2456,6 +2466,10 @@ ssl_NewSocket(PRBool makeLocks) ss->sniSocketConfig = NULL; ss->sniSocketConfigArg = NULL; ss->getClientAuthData = NULL; +#ifdef NSS_PLATFORM_CLIENT_AUTH + ss->getPlatformClientAuthData = NULL; + ss->getPlatformClientAuthDataArg = NULL; +#endif /* NSS_PLATFORM_CLIENT_AUTH */ ss->handleBadCert = NULL; ss->badCertArg = NULL; ss->pkcs11PinArg = NULL; |
