Bug 1530472 - handle issue when server ECC key is in a token that doesn't handle the TLS mechanisms.
authorRobert Relyea <rrelyea@redhat.com>
Thu, 07 Mar 2019 15:53:21 -0800
changeset 15043 cf681f9cffd6107ba759d61336328deb1f26f693
parent 15041 55dfd930f93447ad3daeecdd319e87b59a6ca275
child 15044 2292f1b96d97d0a229e1133a601774306965abe7
push id3294
push userrrelyea@redhat.com
push dateTue, 12 Mar 2019 00:02:04 +0000
bugs1530472
Bug 1530472 - handle issue when server ECC key is in a token that doesn't handle the TLS mechanisms. Differential Revision: https://phabricator.services.mozilla.com/D22625
lib/ssl/ssl3con.c
lib/ssl/sslimpl.h
lib/ssl/tls13con.c
--- a/lib/ssl/ssl3con.c
+++ b/lib/ssl/ssl3con.c
@@ -8621,16 +8621,55 @@ ssl3_HandleClientHello(sslSocket *ss, PR
 alert_loser:
     (void)SSL3_SendAlert(ss, level, desc);
 /* FALLTHRU */
 loser:
     PORT_SetError(errCode);
     return SECFailure;
 }
 
+/* unwrap helper function to handle the case where the wrapKey doesn't wind
+ * up in the correct token for the master secret */
+PK11SymKey *
+ssl_unwrapSymKey(PK11SymKey *wrapKey,
+                 CK_MECHANISM_TYPE wrapType, SECItem *param,
+                 SECItem *wrappedKey,
+                 CK_MECHANISM_TYPE target, CK_ATTRIBUTE_TYPE operation,
+                 int keySize, CK_FLAGS keyFlags, void *pinArg)
+{
+    PK11SymKey *unwrappedKey;
+
+    /* unwrap the master secret. */
+    unwrappedKey = PK11_UnwrapSymKeyWithFlags(wrapKey, wrapType, param,
+                                              wrappedKey, target, operation, keySize,
+                                              keyFlags);
+    if (!unwrappedKey) {
+        PK11SlotInfo *targetSlot = PK11_GetBestSlot(target, pinArg);
+        PK11SymKey *newWrapKey;
+
+        /* it's possible that we failed to unwrap because the wrapKey is in 
+         * a slot that can't handle target. Move the wrapKey to a slot that 
+         * can handle this mechanism and retry the operation */
+        if (targetSlot == NULL) {
+            return NULL;
+        }
+        newWrapKey = PK11_MoveSymKey(targetSlot, CKA_UNWRAP, 0,
+                                     PR_FALSE, wrapKey);
+        PK11_FreeSlot(targetSlot);
+        if (newWrapKey == NULL) {
+            return NULL;
+        }
+        unwrappedKey = PK11_UnwrapSymKeyWithFlags(newWrapKey, wrapType, param,
+                                                  wrappedKey, target, operation, keySize,
+                                                  keyFlags);
+        PK11_FreeSymKey(newWrapKey);
+    }
+    return unwrappedKey;
+}
+
 static SECStatus
 ssl3_UnwrapMasterSecretServer(sslSocket *ss, sslSessionID *sid, PK11SymKey **ms)
 {
     PK11SymKey *wrapKey;
     CK_FLAGS keyFlags = 0;
     SECItem wrappedMS = {
         siBuffer,
         sid->u.ssl3.keys.wrapped_master_secret,
@@ -8642,22 +8681,24 @@ ssl3_UnwrapMasterSecretServer(sslSocket 
     if (!wrapKey) {
         return SECFailure;
     }
 
     if (ss->version > SSL_LIBRARY_VERSION_3_0) { /* isTLS */
         keyFlags = CKF_SIGN | CKF_VERIFY;
     }
 
-    /* unwrap the master secret. */
-    *ms = PK11_UnwrapSymKeyWithFlags(wrapKey, sid->u.ssl3.masterWrapMech,
-                                     NULL, &wrappedMS, CKM_SSL3_MASTER_KEY_DERIVE,
-                                     CKA_DERIVE, SSL3_MASTER_SECRET_LENGTH, keyFlags);
+    *ms = ssl_unwrapSymKey(wrapKey, sid->u.ssl3.masterWrapMech, NULL,
+                           &wrappedMS, CKM_SSL3_MASTER_KEY_DERIVE,
+                           CKA_DERIVE, SSL3_MASTER_SECRET_LENGTH,
+                           keyFlags, ss->pkcs11PinArg);
     PK11_FreeSymKey(wrapKey);
     if (!*ms) {
+        SSL_TRC(10, ("%d: SSL3[%d]: server wrapping key found, but couldn't unwrap MasterSecret. wrapMech=0x%0lx",
+                     SSL_GETPID(), ss->fd, sid->u.ssl3.masterWrapMech));
         return SECFailure;
     }
     return SECSuccess;
 }
 
 static SECStatus
 ssl3_HandleClientHelloPart2(sslSocket *ss,
                             SECItem *suites,
--- a/lib/ssl/sslimpl.h
+++ b/lib/ssl/sslimpl.h
@@ -1729,16 +1729,24 @@ PRBool ssl_AlpnTagAllowed(const sslSocke
 
 void ssl_Trace(const char *format, ...);
 
 void ssl_CacheExternalToken(sslSocket *ss);
 SECStatus ssl_DecodeResumptionToken(sslSessionID *sid, const PRUint8 *encodedTicket,
                                     PRUint32 encodedTicketLen);
 PRBool ssl_IsResumptionTokenUsable(sslSocket *ss, sslSessionID *sid);
 
+/* unwrap helper function to handle the case where the wrapKey doesn't wind
+ *  * up in the correct token for the master secret */
+PK11SymKey *ssl_unwrapSymKey(PK11SymKey *wrapKey,
+                             CK_MECHANISM_TYPE wrapType, SECItem *param,
+                             SECItem *wrappedKey,
+                             CK_MECHANISM_TYPE target, CK_ATTRIBUTE_TYPE operation,
+                             int keySize, CK_FLAGS keyFlags, void *pinArg);
+
 /* Remove when stable. */
 
 SECStatus SSLExp_SetResumptionTokenCallback(PRFileDesc *fd,
                                             SSLResumptionTokenCallback cb,
                                             void *ctx);
 SECStatus SSLExp_SetResumptionToken(PRFileDesc *fd, const PRUint8 *token,
                                     unsigned int len);
 
--- a/lib/ssl/tls13con.c
+++ b/lib/ssl/tls13con.c
@@ -969,23 +969,23 @@ tls13_RecoverWrappedSharedSecret(sslSock
     if (!wrapKey) {
         return SECFailure;
     }
 
     wrappedMS.data = sid->u.ssl3.keys.wrapped_master_secret;
     wrappedMS.len = sid->u.ssl3.keys.wrapped_master_secret_len;
 
     /* unwrap the "master secret" which is actually RMS. */
-    ss->ssl3.hs.resumptionMasterSecret = PK11_UnwrapSymKeyWithFlags(
+    ss->ssl3.hs.resumptionMasterSecret = ssl_unwrapSymKey(
         wrapKey, sid->u.ssl3.masterWrapMech,
         NULL, &wrappedMS,
         CKM_SSL3_MASTER_KEY_DERIVE,
         CKA_DERIVE,
         tls13_GetHashSizeForHash(hashType),
-        CKF_SIGN | CKF_VERIFY);
+        CKF_SIGN | CKF_VERIFY, ss->pkcs11PinArg);
     PK11_FreeSymKey(wrapKey);
     if (!ss->ssl3.hs.resumptionMasterSecret) {
         return SECFailure;
     }
 
     PRINT_KEY(50, (ss, "Recovered RMS", ss->ssl3.hs.resumptionMasterSecret));
 
     return SECSuccess;