From 44a22ec75a0ef4200ba824e9e00b56b735b911a0 Mon Sep 17 00:00:00 2001
Subject: 8294906: Memory leak in PKCS11 NSS TLS server
---
 .../pkcs11/P11TlsKeyMaterialGenerator.java    | 14 ++--
 .../crypto/provider/TLS/TestKeyMaterial.java  | 31 ++++++++-
 .../sun/crypto/provider/TLS/keymatdata.txt    | 34 ++++++++++
 .../security/pkcs11/tls/TestKeyMaterial.java  | 65 +++++++++++++------
 .../sun/security/pkcs11/tls/keymatdata.txt    | 34 ++++++++++
 5 files changed, 151 insertions(+), 27 deletions(-)

diff --git a/jdk/src/share/classes/sun/security/pkcs11/P11TlsKeyMaterialGenerator.java b/jdk/src/share/classes/sun/security/pkcs11/P11TlsKeyMaterialGenerator.java
index f6848278c..4242ff756 100644
--- a/jdk/src/share/classes/sun/security/pkcs11/P11TlsKeyMaterialGenerator.java
+++ b/jdk/src/share/classes/sun/security/pkcs11/P11TlsKeyMaterialGenerator.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2005, 2018, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2005, 2022, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -193,15 +193,19 @@ public final class P11TlsKeyMaterialGenerator extends KeyGeneratorSpi {
             SecretKey clientMacKey, serverMacKey;
 
             // The MAC size may be zero for GCM mode.
-            //
-            // PKCS11 does not support GCM mode as the author made the comment,
-            // so the macBits is unlikely to be zero. It's only a place holder.
             if (macBits != 0) {
                 clientMacKey = P11Key.secretKey
                     (session, out.hClientMacSecret, "MAC", macBits, attributes);
                 serverMacKey = P11Key.secretKey
                     (session, out.hServerMacSecret, "MAC", macBits, attributes);
             } else {
+                // NSS allocates MAC keys even if macBits is zero
+                if (out.hClientMacSecret != CK_INVALID_HANDLE) {
+                    token.p11.C_DestroyObject(session.id(), out.hClientMacSecret);
+                }
+                if (out.hServerMacSecret != CK_INVALID_HANDLE) {
+                    token.p11.C_DestroyObject(session.id(), out.hServerMacSecret);
+                }
                 clientMacKey = null;
                 serverMacKey = null;
             }
@@ -213,6 +217,8 @@ public final class P11TlsKeyMaterialGenerator extends KeyGeneratorSpi {
                 serverCipherKey = P11Key.secretKey(session, out.hServerKey,
                         cipherAlgorithm, expandedKeyBits, attributes);
             } else {
+                assert out.hClientKey == 0;
+                assert out.hServerKey == 0;
                 clientCipherKey = null;
                 serverCipherKey = null;
             }
diff --git a/jdk/test/com/sun/crypto/provider/TLS/TestKeyMaterial.java b/jdk/test/com/sun/crypto/provider/TLS/TestKeyMaterial.java
index 8874070f4..6569c0c4f 100644
--- a/jdk/test/com/sun/crypto/provider/TLS/TestKeyMaterial.java
+++ b/jdk/test/com/sun/crypto/provider/TLS/TestKeyMaterial.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2005, 2022, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -60,6 +60,7 @@ public class TestKeyMaterial extends Utils {
         byte[] clientRandom = null;
         byte[] serverRandom = null;
         String cipherAlgorithm = null;
+        String hashAlgorithm = null; // TLS1.2+ only
         int keyLength = 0;
         int expandedKeyLength = 0;
         int ivLength = 0;
@@ -93,6 +94,8 @@ public class TestKeyMaterial extends Utils {
                 serverRandom = parse(data);
             } else if (line.startsWith("km-cipalg:")) {
                 cipherAlgorithm = data;
+            } else if (line.startsWith("km-hashalg:")) {
+                hashAlgorithm = data;
             } else if (line.startsWith("km-keylen:")) {
                 keyLength = Integer.parseInt(data);
             } else if (line.startsWith("km-explen:")) {
@@ -118,14 +121,36 @@ public class TestKeyMaterial extends Utils {
                 n++;
 
                 KeyGenerator kg =
-                    KeyGenerator.getInstance("SunTlsKeyMaterial", provider);
+                        KeyGenerator.getInstance(minor == 3 ?
+                            "SunTls12KeyMaterial" :
+                            "SunTlsKeyMaterial", provider);
                 SecretKey masterKey =
                     new SecretKeySpec(master, "TlsMasterSecret");
+                int prfHashLength, prfBlockSize;
+
+                if (hashAlgorithm != null) {
+                    switch (hashAlgorithm) {
+                        case "SHA-256":
+                            prfHashLength = 32;
+                            prfBlockSize = 64;
+                            break;
+                        case "SHA-384":
+                            prfHashLength = 48;
+                            prfBlockSize = 128;
+                            break;
+                        default:
+                            throw new RuntimeException("Unexpected hashalg: " +
+                                    hashAlgorithm);
+                    }
+                } else {
+                    prfHashLength = -1;
+                    prfBlockSize = -1;
+                }
                 TlsKeyMaterialParameterSpec spec =
                     new TlsKeyMaterialParameterSpec(masterKey, major, minor,
                         clientRandom, serverRandom, cipherAlgorithm,
                         keyLength, expandedKeyLength, ivLength, macLength,
-                        null, -1, -1);
+                        hashAlgorithm, prfHashLength, prfBlockSize);
 
                 kg.init(spec);
                 TlsKeyMaterialSpec result =
diff --git a/jdk/test/com/sun/crypto/provider/TLS/keymatdata.txt b/jdk/test/com/sun/crypto/provider/TLS/keymatdata.txt
index 391f30000..a3ff869b6 100644
--- a/jdk/test/com/sun/crypto/provider/TLS/keymatdata.txt
+++ b/jdk/test/com/sun/crypto/provider/TLS/keymatdata.txt
@@ -3646,3 +3646,37 @@ km-civ:     17:bd:47:89:54:be:04:23
 km-siv:     34:8a:e8:24:84:38:c4:e1
 km-cmackey: e8:f0:b5:7b:a7:cc:2f:5e:43:ef:d3:dd:4e:8c:f9:6f:51:d7:84:df
 km-smackey: fc:0c:77:20:c2:28:d3:11:ba:57:13:d8:0b:2d:f1:30:89:c6:35:69
+km-master:  f1:05:15:45:33:be:50:d6:88:0b:03:bb:88:9b:ef:d4:3b:98:aa:40:13:71:3c:1c:d9:df:34:c7:50:75:ad:5c:0a:d4:fe:ed:d5:58:6b:ff:2b:ce:c6:12:bc:6b:7e:dc
+km-major:   3
+km-minor:   3
+km-crandom: 42:f3:36:8e:9d:c9:69:3e:c1:8a:38:d3:e0:ec:2b:58:c2:e0:0c:de:4f:f3:af:51:d2:5c:bc:b2:c3:3b:1e:56
+km-srandom: 42:f3:36:8e:fa:fd:23:3e:fd:f9:bc:88:3c:98:93:f3:c3:1d:9c:2a:4a:3b:02:a7:40:d4:64:04:59:e9:65:97
+km-cipalg:  AES
+km-hashalg: SHA-256
+km-keylen:  16
+km-explen:  0
+km-ivlen:   4
+km-maclen:  0
+km-ccipkey: 60:7a:45:a9:6e:76:58:ea:d9:44:c5:25:f8:92:f1:26
+km-scipkey: 42:c0:ed:75:a2:51:21:7c:50:74:9d:78:9a:f7:35:2b
+km-civ:     a1:3c:3e:4a
+km-siv:     85:ab:ee:70
+km-cmackey: (null)
+km-smackey: (null)
+km-master:  f1:05:15:45:33:be:50:d6:88:0b:03:bb:88:9b:ef:d4:3b:98:aa:40:13:71:3c:1c:d9:df:34:c7:50:75:ad:5c:0a:d4:fe:ed:d5:58:6b:ff:2b:ce:c6:12:bc:6b:7e:dc
+km-major:   3
+km-minor:   3
+km-crandom: 42:f3:36:8e:9d:c9:69:3e:c1:8a:38:d3:e0:ec:2b:58:c2:e0:0c:de:4f:f3:af:51:d2:5c:bc:b2:c3:3b:1e:56
+km-srandom: 42:f3:36:8e:fa:fd:23:3e:fd:f9:bc:88:3c:98:93:f3:c3:1d:9c:2a:4a:3b:02:a7:40:d4:64:04:59:e9:65:97
+km-cipalg:  AES
+km-hashalg: SHA-384
+km-keylen:  32
+km-explen:  0
+km-ivlen:   4
+km-maclen:  0
+km-ccipkey: 3c:03:17:61:1e:88:4a:aa:01:4c:ac:6c:f8:bb:91:c3:0e:ec:57:c7:bf:07:ff:eb:49:22:f9:80:12:64:72:2a
+km-scipkey: f8:00:8e:b2:dc:25:98:f1:97:00:55:28:60:a3:65:da:42:89:18:bb:40:94:53:d2:75:2a:29:e5:aa:94:1d:7a
+km-civ:     24:02:76:6f
+km-siv:     3b:6d:33:5a
+km-cmackey: (null)
+km-smackey: (null)
\ No newline at end of file
diff --git a/jdk/test/sun/security/pkcs11/tls/TestKeyMaterial.java b/jdk/test/sun/security/pkcs11/tls/TestKeyMaterial.java
index 534398a1a..e138a5b1d 100644
--- a/jdk/test/sun/security/pkcs11/tls/TestKeyMaterial.java
+++ b/jdk/test/sun/security/pkcs11/tls/TestKeyMaterial.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2005, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2005, 2022, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -21,9 +21,9 @@
  * questions.
  */
 
-/**
+/*
  * @test
- * @bug 6316539
+ * @bug 6316539 8136355 8294906
  * @summary Known-answer-test for TlsKeyMaterial generator
  * @author Andreas Sterbenz
  * @library ..
@@ -34,12 +34,16 @@
 import java.io.BufferedReader;
 import java.nio.file.Files;
 import java.nio.file.Paths;
+import java.security.InvalidAlgorithmParameterException;
 import java.security.Provider;
+import java.security.ProviderException;
 import java.util.Arrays;
+
 import javax.crypto.KeyGenerator;
 import javax.crypto.SecretKey;
 import javax.crypto.spec.IvParameterSpec;
 import javax.crypto.spec.SecretKeySpec;
+
 import sun.security.internal.spec.TlsKeyMaterialParameterSpec;
 import sun.security.internal.spec.TlsKeyMaterialSpec;
 
@@ -48,6 +52,7 @@ public class TestKeyMaterial extends PKCS11Test {
     private static final int PREFIX_LENGTH = "km-master:  ".length();
 
     public static void main(String[] args) throws Exception {
+        System.out.println("NSS Version: " + getNSSVersion());
         main(new TestKeyMaterial(), args);
     }
 
@@ -70,6 +75,7 @@ public class TestKeyMaterial extends PKCS11Test {
             byte[] clientRandom = null;
             byte[] serverRandom = null;
             String cipherAlgorithm = null;
+            String hashAlgorithm = null; // TLS1.2+ only
             int keyLength = 0;
             int expandedKeyLength = 0;
             int ivLength = 0;
@@ -103,6 +109,8 @@ public class TestKeyMaterial extends PKCS11Test {
                     serverRandom = parse(data);
                 } else if (line.startsWith("km-cipalg:")) {
                     cipherAlgorithm = data;
+                } else if (line.startsWith("km-hashalg:")) {
+                    hashAlgorithm = data;
                 } else if (line.startsWith("km-keylen:")) {
                     keyLength = Integer.parseInt(data);
                 } else if (line.startsWith("km-explen:")) {
@@ -128,30 +136,47 @@ public class TestKeyMaterial extends PKCS11Test {
                     n++;
 
                     KeyGenerator kg =
-                        KeyGenerator.getInstance("SunTlsKeyMaterial", provider);
+                        KeyGenerator.getInstance(minor == 3 ?
+                                "SunTls12KeyMaterial" :
+                                "SunTlsKeyMaterial", provider);
                     SecretKey masterKey =
                         new SecretKeySpec(master, "TlsMasterSecret");
+                    // prfHashLength and prfBlockSize are ignored by PKCS11 provider
                     TlsKeyMaterialParameterSpec spec =
                         new TlsKeyMaterialParameterSpec(masterKey, major, minor,
                         clientRandom, serverRandom, cipherAlgorithm,
                         keyLength, expandedKeyLength, ivLength, macLength,
-                        null, -1, -1);
-
-                    kg.init(spec);
-                    TlsKeyMaterialSpec result =
-                        (TlsKeyMaterialSpec)kg.generateKey();
-                    match(lineNumber, clientCipherBytes,
-                        result.getClientCipherKey(), cipherAlgorithm);
-                    match(lineNumber, serverCipherBytes,
-                        result.getServerCipherKey(), cipherAlgorithm);
-                    match(lineNumber, clientIv, result.getClientIv(), "");
-                    match(lineNumber, serverIv, result.getServerIv(), "");
-                    match(lineNumber, clientMacBytes, result.getClientMacKey(), "");
-                    match(lineNumber, serverMacBytes, result.getServerMacKey(), "");
-
-                } else {
+                        hashAlgorithm, -1 /*ignored*/, -1 /*ignored*/);
+
+                    try {
+                        kg.init(spec);
+                        TlsKeyMaterialSpec result =
+                            (TlsKeyMaterialSpec)kg.generateKey();
+                        match(lineNumber, clientCipherBytes,
+                            result.getClientCipherKey(), cipherAlgorithm);
+                        match(lineNumber, serverCipherBytes,
+                            result.getServerCipherKey(), cipherAlgorithm);
+                        match(lineNumber, clientIv, result.getClientIv(), "");
+                        match(lineNumber, serverIv, result.getServerIv(), "");
+                        match(lineNumber, clientMacBytes, result.getClientMacKey(), "");
+                        match(lineNumber, serverMacBytes, result.getServerMacKey(), "");
+                    } catch (ProviderException pe) {
+                        if (provider.getName().indexOf("NSS") != -1) {
+                            Throwable t = pe.getCause();
+                            if (expandedKeyLength != 0
+                                    && t.getMessage().indexOf(
+                                            "CKR_MECHANISM_PARAM_INVALID") != -1) {
+                                // NSS removed support for export-grade cipher suites in 3.28,
+                                // see https://bugzilla.mozilla.org/show_bug.cgi?id=1252849
+                                System.out.println("Ignore known NSS failure on CKR_MECHANISM_PARAM_INVALID");
+                                continue;
+                            }
+                        }
+                        throw pe;
+                    }
+               } else {
                     throw new Exception("Unknown line: " + line);
-                }
+               }
             }
             if (n == 0) {
                 throw new Exception("no tests");
diff --git a/jdk/test/sun/security/pkcs11/tls/keymatdata.txt b/jdk/test/sun/security/pkcs11/tls/keymatdata.txt
index 391f30000..1d1ee6369 100644
--- a/jdk/test/sun/security/pkcs11/tls/keymatdata.txt
+++ b/jdk/test/sun/security/pkcs11/tls/keymatdata.txt
@@ -3646,3 +3646,37 @@ km-civ:     17:bd:47:89:54:be:04:23
 km-siv:     34:8a:e8:24:84:38:c4:e1
 km-cmackey: e8:f0:b5:7b:a7:cc:2f:5e:43:ef:d3:dd:4e:8c:f9:6f:51:d7:84:df
 km-smackey: fc:0c:77:20:c2:28:d3:11:ba:57:13:d8:0b:2d:f1:30:89:c6:35:69
+km-master:  f1:05:15:45:33:be:50:d6:88:0b:03:bb:88:9b:ef:d4:3b:98:aa:40:13:71:3c:1c:d9:df:34:c7:50:75:ad:5c:0a:d4:fe:ed:d5:58:6b:ff:2b:ce:c6:12:bc:6b:7e:dc
+km-major:   3
+km-minor:   3
+km-crandom: 42:f3:36:8e:9d:c9:69:3e:c1:8a:38:d3:e0:ec:2b:58:c2:e0:0c:de:4f:f3:af:51:d2:5c:bc:b2:c3:3b:1e:56
+km-srandom: 42:f3:36:8e:fa:fd:23:3e:fd:f9:bc:88:3c:98:93:f3:c3:1d:9c:2a:4a:3b:02:a7:40:d4:64:04:59:e9:65:97
+km-cipalg:  AES
+km-hashalg: SHA-256
+km-keylen:  16
+km-explen:  0
+km-ivlen:   4
+km-maclen:  0
+km-ccipkey: 60:7a:45:a9:6e:76:58:ea:d9:44:c5:25:f8:92:f1:26
+km-scipkey: 42:c0:ed:75:a2:51:21:7c:50:74:9d:78:9a:f7:35:2b
+km-civ:     a1:3c:3e:4a
+km-siv:     85:ab:ee:70
+km-cmackey: (null)
+km-smackey: (null)
+km-master:  f1:05:15:45:33:be:50:d6:88:0b:03:bb:88:9b:ef:d4:3b:98:aa:40:13:71:3c:1c:d9:df:34:c7:50:75:ad:5c:0a:d4:fe:ed:d5:58:6b:ff:2b:ce:c6:12:bc:6b:7e:dc
+km-major:   3
+km-minor:   3
+km-crandom: 42:f3:36:8e:9d:c9:69:3e:c1:8a:38:d3:e0:ec:2b:58:c2:e0:0c:de:4f:f3:af:51:d2:5c:bc:b2:c3:3b:1e:56
+km-srandom: 42:f3:36:8e:fa:fd:23:3e:fd:f9:bc:88:3c:98:93:f3:c3:1d:9c:2a:4a:3b:02:a7:40:d4:64:04:59:e9:65:97
+km-cipalg:  AES
+km-hashalg: SHA-384
+km-keylen:  32
+km-explen:  0
+km-ivlen:   4
+km-maclen:  0
+km-ccipkey: 3c:03:17:61:1e:88:4a:aa:01:4c:ac:6c:f8:bb:91:c3:0e:ec:57:c7:bf:07:ff:eb:49:22:f9:80:12:64:72:2a
+km-scipkey: f8:00:8e:b2:dc:25:98:f1:97:00:55:28:60:a3:65:da:42:89:18:bb:40:94:53:d2:75:2a:29:e5:aa:94:1d:7a
+km-civ:     24:02:76:6f
+km-siv:     3b:6d:33:5a
+km-cmackey: (null)
+km-smackey: (null)
-- 
2.22.0

