| diff -puN -r a/net/third_party/nss/ssl/ssl3con.c b/net/third_party/nss/ssl/ssl3con.c |
| --- a/net/third_party/nss/ssl/ssl3con.c 2012-11-09 15:34:12.258133766 -0800 |
| +++ b/net/third_party/nss/ssl/ssl3con.c 2012-11-09 15:35:08.488958561 -0800 |
| @@ -2033,6 +2033,9 @@ ssl3_ClientAuthTokenPresent(sslSessionID |
| PRBool isPresent = PR_TRUE; |
| |
| /* we only care if we are doing client auth */ |
| + /* If NSS_PLATFORM_CLIENT_AUTH is defined and a platformClientKey is being |
| + * used, u.ssl3.clAuthValid will be false and this function will always |
| + * return PR_TRUE. */ |
| if (!sid || !sid->u.ssl3.clAuthValid) { |
| return PR_TRUE; |
| } |
| @@ -5226,24 +5229,33 @@ ssl3_SendCertificateVerify(sslSocket *ss |
| } |
| |
| isTLS = (PRBool)(ss->ssl3.pwSpec->version > SSL_LIBRARY_VERSION_3_0); |
| - rv = ssl3_SignHashes(&hashes, ss->ssl3.clientPrivateKey, &buf, isTLS); |
| - if (rv == SECSuccess) { |
| - PK11SlotInfo * slot; |
| - sslSessionID * sid = ss->sec.ci.sid; |
| + if (ss->ssl3.platformClientKey) { |
| +#ifdef NSS_PLATFORM_CLIENT_AUTH |
| + rv = ssl3_PlatformSignHashes(&hashes, ss->ssl3.platformClientKey, |
| + &buf, isTLS); |
| + ssl_FreePlatformKey(ss->ssl3.platformClientKey); |
| + ss->ssl3.platformClientKey = (PlatformKey)NULL; |
| +#endif /* NSS_PLATFORM_CLIENT_AUTH */ |
| + } else { |
| + rv = ssl3_SignHashes(&hashes, ss->ssl3.clientPrivateKey, &buf, isTLS); |
| + if (rv == SECSuccess) { |
| + PK11SlotInfo * slot; |
| + sslSessionID * sid = ss->sec.ci.sid; |
| |
| - /* Remember the info about the slot that did the signing. |
| - ** Later, when doing an SSL restart handshake, verify this. |
| - ** These calls are mere accessors, and can't fail. |
| - */ |
| - slot = PK11_GetSlotFromPrivateKey(ss->ssl3.clientPrivateKey); |
| - sid->u.ssl3.clAuthSeries = PK11_GetSlotSeries(slot); |
| - sid->u.ssl3.clAuthSlotID = PK11_GetSlotID(slot); |
| - sid->u.ssl3.clAuthModuleID = PK11_GetModuleID(slot); |
| - sid->u.ssl3.clAuthValid = PR_TRUE; |
| - PK11_FreeSlot(slot); |
| + /* Remember the info about the slot that did the signing. |
| + ** Later, when doing an SSL restart handshake, verify this. |
| + ** These calls are mere accessors, and can't fail. |
| + */ |
| + slot = PK11_GetSlotFromPrivateKey(ss->ssl3.clientPrivateKey); |
| + sid->u.ssl3.clAuthSeries = PK11_GetSlotSeries(slot); |
| + sid->u.ssl3.clAuthSlotID = PK11_GetSlotID(slot); |
| + sid->u.ssl3.clAuthModuleID = PK11_GetModuleID(slot); |
| + sid->u.ssl3.clAuthValid = PR_TRUE; |
| + PK11_FreeSlot(slot); |
| + } |
| + SECKEY_DestroyPrivateKey(ss->ssl3.clientPrivateKey); |
| + ss->ssl3.clientPrivateKey = NULL; |
| } |
| - SECKEY_DestroyPrivateKey(ss->ssl3.clientPrivateKey); |
| - ss->ssl3.clientPrivateKey = NULL; |
| if (rv != SECSuccess) { |
| goto done; /* err code was set by ssl3_SignHashes */ |
| } |
| @@ -5311,6 +5323,12 @@ ssl3_HandleServerHello(sslSocket *ss, SS |
| 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 */ |
| |
| temp = ssl3_ConsumeHandshakeNumber(ss, 2, &b, &length); |
| if (temp < 0) { |
| @@ -5901,6 +5919,10 @@ ssl3_HandleCertificateRequest(sslSocket |
| 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)); |
| @@ -5917,6 +5939,7 @@ ssl3_HandleCertificateRequest(sslSocket |
| PORT_Assert(ss->ssl3.clientCertChain == NULL); |
| PORT_Assert(ss->ssl3.clientCertificate == NULL); |
| PORT_Assert(ss->ssl3.clientPrivateKey == NULL); |
| + PORT_Assert(ss->ssl3.platformClientKey == (PlatformKey)NULL); |
| |
| isTLS = (PRBool)(ss->ssl3.prSpec->version > SSL_LIBRARY_VERSION_3_0); |
| rv = ssl3_ConsumeHandshakeVariable(ss, &cert_types, 1, &b, &length); |
| @@ -5983,6 +6006,18 @@ ssl3_HandleCertificateRequest(sslSocket |
| desc = no_certificate; |
| ss->ssl3.hs.ws = wait_hello_done; |
| |
| +#ifdef NSS_PLATFORM_CLIENT_AUTH |
| + if (ss->getPlatformClientAuthData != NULL) { |
| + /* 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, |
| + &ss->ssl3.clientCertificate, |
| + &ss->ssl3.clientPrivateKey); |
| + } else |
| +#endif |
| if (ss->getClientAuthData == NULL) { |
| rv = SECFailure; /* force it to send a no_certificate alert */ |
| } else { |
| @@ -5992,12 +6029,52 @@ ssl3_HandleCertificateRequest(sslSocket |
| &ss->ssl3.clientCertificate, |
| &ss->ssl3.clientPrivateKey); |
| } |
| + |
| switch (rv) { |
| case SECWouldBlock: /* getClientAuthData has put up a dialog box. */ |
| ssl3_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; |
| + } |
| + /* Fall through to NSS client auth check */ |
| + } else { |
| + 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; |
| + } |
| + break; /* not an error */ |
| + } |
| +#endif /* NSS_PLATFORM_CLIENT_AUTH */ |
| /* check what the callback function returned */ |
| if ((!ss->ssl3.clientCertificate) || (!ss->ssl3.clientPrivateKey)) { |
| /* we are missing either the key or cert */ |
| @@ -6060,6 +6137,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; |
| } |
| |
| @@ -6134,7 +6215,8 @@ ssl3_SendClientSecondRound(sslSocket *ss |
| |
| sendClientCert = !ss->ssl3.sendEmptyCert && |
| ss->ssl3.clientCertChain != NULL && |
| - ss->ssl3.clientPrivateKey != NULL; |
| + (ss->ssl3.platformClientKey || |
| + ss->ssl3.clientPrivateKey != NULL); |
| |
| /* We must wait for the server's certificate to be authenticated before |
| * sending the client certificate in order to disclosing the client |
| @@ -10446,6 +10528,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 -puN -r a/net/third_party/nss/ssl/ssl3ext.c b/net/third_party/nss/ssl/ssl3ext.c |
| --- a/net/third_party/nss/ssl/ssl3ext.c 2012-11-09 15:34:12.258133766 -0800 |
| +++ b/net/third_party/nss/ssl/ssl3ext.c 2012-11-09 15:35:08.488958561 -0800 |
| @@ -11,8 +11,8 @@ |
| #include "nssrenam.h" |
| #include "nss.h" |
| #include "ssl.h" |
| -#include "sslproto.h" |
| #include "sslimpl.h" |
| +#include "sslproto.h" |
| #include "pk11pub.h" |
| #ifdef NO_PKCS11_BYPASS |
| #include "blapit.h" |
| diff -puN -r a/net/third_party/nss/ssl/sslauth.c b/net/third_party/nss/ssl/sslauth.c |
| --- a/net/third_party/nss/ssl/sslauth.c 2012-11-09 15:27:15.952019947 -0800 |
| +++ b/net/third_party/nss/ssl/sslauth.c 2012-11-09 15:35:08.488958561 -0800 |
| @@ -219,6 +219,28 @@ SSL_GetClientAuthDataHook(PRFileDesc *s, |
| 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 -puN -r a/net/third_party/nss/ssl/ssl.h b/net/third_party/nss/ssl/ssl.h |
| --- a/net/third_party/nss/ssl/ssl.h 2012-11-09 15:34:12.258133766 -0800 |
| +++ b/net/third_party/nss/ssl/ssl.h 2012-11-09 15:35:08.488958561 -0800 |
| @@ -483,6 +483,48 @@ typedef SECStatus (PR_CALLBACK *SSLGetCl |
| SSL_IMPORT SECStatus SSL_GetClientAuthDataHook(PRFileDesc *fd, |
| SSLGetClientAuthData f, void *a); |
| |
| +/* |
| + * Prototype for SSL callback to get client auth data from the application, |
| + * optionally using the underlying platform's cryptographic primitives. |
| + * To use the platform cryptographic primitives, caNames and pRetCerts |
| + * should be set. To use NSS, pRetNSSCert and pRetNSSKey should be set. |
| + * 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: A pointer to a PCERT_KEY_CONTEXT that was allocated |
| + * via PORT_Alloc(). Ownership of the PCERT_KEY_CONTEXT |
| + * is transferred to NSS, which will free via |
| + * PORT_Free(). |
| + * - Mac OS X: A pointer to a SecKeyRef. Ownership is |
| + * transferred to NSS, which will free via CFRelease(). |
| + * pRetNSSCert - pointer to pointer to NSS cert, for return of cert. |
| + * pRetNSSKey - pointer to NSS key pointer, for return of key. |
| + */ |
| +typedef SECStatus (PR_CALLBACK *SSLGetPlatformClientAuthData)(void *arg, |
| + PRFileDesc *fd, |
| + CERTDistNames *caNames, |
| + CERTCertList **pRetCerts,/*return */ |
| + void **pRetKey,/* return */ |
| + CERTCertificate **pRetNSSCert,/*return */ |
| + SECKEYPrivateKey **pRetNSSKey);/* return */ |
| + |
| +/* |
| + * Set the client side callback for SSL to retrieve user's private key |
| + * and certificate. |
| + * Note: If a platform client auth callback is set, the callback configured by |
| + * SSL_GetClientAuthDataHook, if any, will not be called. |
| + * |
| + * 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 -puN -r a/net/third_party/nss/ssl/sslimpl.h b/net/third_party/nss/ssl/sslimpl.h |
| --- a/net/third_party/nss/ssl/sslimpl.h 2012-11-09 15:34:12.258133766 -0800 |
| +++ b/net/third_party/nss/ssl/sslimpl.h 2012-11-09 15:36:42.600338478 -0800 |
| @@ -32,6 +32,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. |
| @@ -446,6 +455,14 @@ typedef SECStatus (*SSLCompressor)(void |
| int inlen); |
| typedef SECStatus (*SSLDestroy)(void *context, PRBool freeit); |
| |
| +#if defined(NSS_PLATFORM_CLIENT_AUTH) && defined(XP_WIN32) |
| +typedef PCERT_KEY_CONTEXT PlatformKey; |
| +#elif defined(NSS_PLATFORM_CLIENT_AUTH) && defined(XP_MACOSX) |
| +typedef SecKeyRef PlatformKey; |
| +#else |
| +typedef void *PlatformKey; |
| +#endif |
| + |
| |
| |
| /* |
| @@ -870,6 +887,10 @@ struct ssl3StateStr { |
| |
| CERTCertificate * clientCertificate; /* used by client */ |
| SECKEYPrivateKey * clientPrivateKey; /* used by client */ |
| + /* platformClientKey is present even when NSS_PLATFORM_CLIENT_AUTH is not |
| + * defined in order to allow cleaner conditional code. |
| + * At most one of clientPrivateKey and platformClientKey may be set. */ |
| + PlatformKey platformClientKey; /* used by client */ |
| CERTCertificateList *clientCertChain; /* used by client */ |
| PRBool sendEmptyCert; /* used by client */ |
| |
| @@ -1127,6 +1148,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; |
| @@ -1700,7 +1725,6 @@ extern void ssl_FreePRSocket(PRFileDesc |
| * various ciphers */ |
| extern int ssl3_config_match_init(sslSocket *); |
| |
| - |
| /* Create a new ref counted key pair object from two keys. */ |
| extern ssl3KeyPair * ssl3_NewKeyPair( SECKEYPrivateKey * privKey, |
| SECKEYPublicKey * pubKey); |
| @@ -1740,6 +1764,26 @@ extern SECStatus ssl_InitSessionCacheLoc |
| |
| extern SECStatus ssl_FreeSessionCacheLocks(void); |
| |
| +/***************** platform client auth ****************/ |
| + |
| +#ifdef NSS_PLATFORM_CLIENT_AUTH |
| +// Releases the platform key. |
| +extern void ssl_FreePlatformKey(PlatformKey key); |
| + |
| +// 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 */ |
| |
| /**************** DTLS-specific functions **************/ |
| extern void dtls_FreeQueuedMessage(DTLSQueuedMessage *msg); |
| diff -puN -r a/net/third_party/nss/ssl/sslplatf.c b/net/third_party/nss/ssl/sslplatf.c |
| --- a/net/third_party/nss/ssl/sslplatf.c 1969-12-31 16:00:00.000000000 -0800 |
| +++ b/net/third_party/nss/ssl/sslplatf.c 2012-11-09 15:35:08.498958708 -0800 |
| @@ -0,0 +1,399 @@ |
| +/* |
| + * 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) |
| +{ |
| + if (key) { |
| + if (key->dwKeySpec != CERT_NCRYPT_KEY_SPEC) |
| + CryptReleaseContext(key->hCryptProv, 0); |
| + /* FIXME(rsleevi): Close CNG keys. */ |
| + PORT_Free(key); |
| + } |
| +} |
| + |
| +SECStatus |
| +ssl3_PlatformSignHashes(SSL3Hashes *hash, PlatformKey key, SECItem *buf, |
| + PRBool isTLS) |
| +{ |
| + SECStatus rv = SECFailure; |
| + PRBool doDerEncode = PR_FALSE; |
| + SECItem hashItem; |
| + 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->hCryptProv, key->dwKeySpec, &hKey)) { |
| + if (GetLastError() == NTE_NO_KEY) { |
| + PORT_SetError(SEC_ERROR_NO_KEY); |
| + } else { |
| + 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: |
| + 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_INVALID_KEY); |
| + goto done; |
| + } |
| + PRINT_BUF(60, (NULL, "hash(es) to be signed", hashItem.data, hashItem.len)); |
| + |
| + if (!CryptCreateHash(key->hCryptProv, hashAlg, 0, 0, &hHash)) { |
| + PORT_SetError(SSL_ERROR_SIGN_HASHES_FAILURE); |
| + goto done; |
| + } |
| + argLen = sizeof(hashLen); |
| + if (!CryptGetHashParam(hHash, HP_HASHSIZE, (BYTE*)&hashLen, &argLen, 0)) { |
| + PORT_SetError(SSL_ERROR_SIGN_HASHES_FAILURE); |
| + goto done; |
| + } |
| + if (hashLen != hashItem.len) { |
| + PORT_SetError(SSL_ERROR_SIGN_HASHES_FAILURE); |
| + goto done; |
| + } |
| + if (!CryptSetHashParam(hHash, HP_HASHVAL, (BYTE*)hashItem.data, 0)) { |
| + PORT_SetError(SSL_ERROR_SIGN_HASHES_FAILURE); |
| + goto done; |
| + } |
| + if (!CryptSignHash(hHash, key->dwKeySpec, NULL, 0, |
| + NULL, &signatureLen) || signatureLen == 0) { |
| + PORT_SetError(SSL_ERROR_SIGN_HASHES_FAILURE); |
| + goto done; |
| + } |
| + buf->data = (unsigned char *)PORT_Alloc(signatureLen); |
| + if (!buf->data) |
| + goto done; /* error code was set. */ |
| + |
| + if (!CryptSignHash(hHash, key->dwKeySpec, NULL, 0, |
| + (BYTE*)buf->data, &signatureLen)) { |
| + PORT_SetError(SSL_ERROR_SIGN_HASHES_FAILURE); |
| + goto done; |
| + } |
| + buf->len = signatureLen; |
| + |
| + /* 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); |
| + } |
| + } else { |
| + rv = SECSuccess; |
| + } |
| + |
| + PRINT_BUF(60, (NULL, "signed hashes", buf->data, buf->len)); |
| +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> |
| + |
| +void |
| +ssl_FreePlatformKey(PlatformKey key) |
| +{ |
| + CFRelease(key); |
| +} |
| + |
| +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_NO_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->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) { |
| + PORT_SetError(SSL_ERROR_SIGN_HASHES_FAILURE); |
| + goto done; |
| + } |
| + |
| + signatureData.Length = signatureLen; |
| + signatureData.Data = (uint8*)buf->data; |
| + |
| + cssmRv = CSSM_CSP_CreateSignatureContext(cspHandle, sigAlg, cssmCreds, |
| + cssmKey, &cssmSignature); |
| + if (cssmRv) { |
| + PORT_SetError(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) { |
| + PORT_SetError(SSL_ERROR_SIGN_HASHES_FAILURE); |
| + goto done; |
| + } |
| + } |
| + |
| + cssmRv = CSSM_SignData(cssmSignature, &hashData, 1, CSSM_ALGID_NONE, |
| + &signatureData); |
| + if (cssmRv) { |
| + PORT_SetError(SSL_ERROR_SIGN_HASHES_FAILURE); |
| + goto done; |
| + } |
| + buf->len = signatureData.Length; |
| + |
| + 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); |
| + } |
| + } else { |
| + rv = SECSuccess; |
| + } |
| + |
| + PRINT_BUF(60, (NULL, "signed hashes", buf->data, buf->len)); |
| +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) |
| +{ |
| +} |
| + |
| +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 -puN -r a/net/third_party/nss/ssl/sslsock.c b/net/third_party/nss/ssl/sslsock.c |
| --- a/net/third_party/nss/ssl/sslsock.c 2012-11-09 15:34:12.268133912 -0800 |
| +++ b/net/third_party/nss/ssl/sslsock.c 2012-11-09 15:35:08.498958708 -0800 |
| @@ -335,6 +335,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; |
| @@ -1712,6 +1716,12 @@ SSL_ReconfigFD(PRFileDesc *model, PRFile |
| 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) |
| @@ -2942,6 +2952,10 @@ ssl_NewSocket(PRBool makeLocks, SSLProto |
| 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; |