mirror of
https://github.com/openjdk/jdk.git
synced 2025-08-26 22:34:27 +02:00
8328119: Support HKDF in SunPKCS11 (Preview)
8346720: Support Generic keys in SunPKCS11 SecretKeyFactory Co-authored-by: Francisco Ferrari Bihurriet <fferrari@openjdk.org> Co-authored-by: Martin Balao <mbalao@openjdk.org> Reviewed-by: valeriep, kdriver, weijun
This commit is contained in:
parent
28e744dc64
commit
6ddbcc34c0
16 changed files with 1582 additions and 66 deletions
|
@ -156,6 +156,7 @@ module java.base {
|
||||||
java.compiler,
|
java.compiler,
|
||||||
java.desktop, // for ScopedValue
|
java.desktop, // for ScopedValue
|
||||||
jdk.compiler,
|
jdk.compiler,
|
||||||
|
jdk.crypto.cryptoki, // participates in preview features
|
||||||
jdk.incubator.vector, // participates in preview features
|
jdk.incubator.vector, // participates in preview features
|
||||||
jdk.jartool, // participates in preview features
|
jdk.jartool, // participates in preview features
|
||||||
jdk.jdeps, // participates in preview features
|
jdk.jdeps, // participates in preview features
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 2014, 2023, Oracle and/or its affiliates. All rights reserved.
|
* Copyright (c) 2014, 2025, Oracle and/or its affiliates. All rights reserved.
|
||||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
*
|
*
|
||||||
* This code is free software; you can redistribute it and/or modify it
|
* This code is free software; you can redistribute it and/or modify it
|
||||||
|
@ -23,6 +23,8 @@
|
||||||
* questions.
|
* questions.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
import jdk.internal.javac.ParticipatesInPreview;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Provides the implementation of the SunPKCS11 security provider.
|
* Provides the implementation of the SunPKCS11 security provider.
|
||||||
*
|
*
|
||||||
|
@ -31,6 +33,7 @@
|
||||||
* @moduleGraph
|
* @moduleGraph
|
||||||
* @since 9
|
* @since 9
|
||||||
*/
|
*/
|
||||||
|
@ParticipatesInPreview
|
||||||
module jdk.crypto.cryptoki {
|
module jdk.crypto.cryptoki {
|
||||||
provides java.security.Provider with sun.security.pkcs11.SunPKCS11;
|
provides java.security.Provider with sun.security.pkcs11.SunPKCS11;
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,367 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2025, Red Hat, Inc.
|
||||||
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
|
*
|
||||||
|
* This code is free software; you can redistribute it and/or modify it
|
||||||
|
* under the terms of the GNU General Public License version 2 only, as
|
||||||
|
* published by the Free Software Foundation. Oracle designates this
|
||||||
|
* particular file as subject to the "Classpath" exception as provided
|
||||||
|
* by Oracle in the LICENSE file that accompanied this code.
|
||||||
|
*
|
||||||
|
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||||
|
* version 2 for more details (a copy is included in the LICENSE file that
|
||||||
|
* accompanied this code).
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License version
|
||||||
|
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||||
|
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||||
|
*
|
||||||
|
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||||
|
* or visit www.oracle.com if you need additional information or have any
|
||||||
|
* questions.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package sun.security.pkcs11;
|
||||||
|
|
||||||
|
import javax.crypto.KDFParameters;
|
||||||
|
import javax.crypto.KDFSpi;
|
||||||
|
import javax.crypto.SecretKey;
|
||||||
|
import javax.crypto.spec.HKDFParameterSpec;
|
||||||
|
import javax.crypto.spec.SecretKeySpec;
|
||||||
|
import java.security.*;
|
||||||
|
import java.security.spec.*;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import static sun.security.pkcs11.TemplateManager.*;
|
||||||
|
import sun.security.pkcs11.wrapper.*;
|
||||||
|
import static sun.security.pkcs11.wrapper.PKCS11Constants.*;
|
||||||
|
|
||||||
|
final class P11HKDF extends KDFSpi {
|
||||||
|
private final Token token;
|
||||||
|
private final P11SecretKeyFactory.HKDFKeyInfo svcKi;
|
||||||
|
private static final SecretKey EMPTY_KEY = new SecretKey() {
|
||||||
|
@Override
|
||||||
|
public String getAlgorithm() {
|
||||||
|
return "Generic";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getFormat() {
|
||||||
|
return "RAW";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public byte[] getEncoded() {
|
||||||
|
return new byte[0];
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
private static KDFParameters requireNull(KDFParameters kdfParameters,
|
||||||
|
String message) throws InvalidAlgorithmParameterException {
|
||||||
|
if (kdfParameters != null) {
|
||||||
|
throw new InvalidAlgorithmParameterException(message);
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void checkMechanismEnabled(long mechanism) {
|
||||||
|
if (!token.provider.config.isEnabled(mechanism)) {
|
||||||
|
throw new ProviderException("Mechanism " +
|
||||||
|
Functions.getMechanismName(mechanism) +
|
||||||
|
" is disabled through 'enabledMechanisms' or " +
|
||||||
|
"'disabledMechanisms' in " + token.provider.getName() +
|
||||||
|
" configuration.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
P11HKDF(Token token, String algorithm, KDFParameters kdfParameters)
|
||||||
|
throws InvalidAlgorithmParameterException {
|
||||||
|
super(requireNull(kdfParameters,
|
||||||
|
algorithm + " does not support parameters"));
|
||||||
|
this.token = token;
|
||||||
|
this.svcKi = P11SecretKeyFactory.getHKDFKeyInfo(algorithm);
|
||||||
|
assert this.svcKi != null : "Unsupported HKDF algorithm " + algorithm;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected KDFParameters engineGetParameters() {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected SecretKey engineDeriveKey(String alg,
|
||||||
|
AlgorithmParameterSpec derivationSpec)
|
||||||
|
throws InvalidAlgorithmParameterException,
|
||||||
|
NoSuchAlgorithmException {
|
||||||
|
if (alg == null) {
|
||||||
|
throw new NullPointerException("the algorithm for the " +
|
||||||
|
"SecretKey return value must not be null");
|
||||||
|
}
|
||||||
|
if (alg.isEmpty()) {
|
||||||
|
throw new NoSuchAlgorithmException("the algorithm for the " +
|
||||||
|
"SecretKey return value must not be empty");
|
||||||
|
}
|
||||||
|
return derive(alg, derivationSpec, SecretKey.class);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected byte[] engineDeriveData(AlgorithmParameterSpec derivationSpec)
|
||||||
|
throws InvalidAlgorithmParameterException {
|
||||||
|
return derive("Generic", derivationSpec, byte[].class);
|
||||||
|
}
|
||||||
|
|
||||||
|
private <T> T derive(String alg, AlgorithmParameterSpec derivationSpec,
|
||||||
|
Class<T> retType) throws InvalidAlgorithmParameterException {
|
||||||
|
SecretKey baseKey;
|
||||||
|
SecretKey salt = EMPTY_KEY;
|
||||||
|
byte[] info = null;
|
||||||
|
int outLen;
|
||||||
|
boolean isExtract = false, isExpand = false;
|
||||||
|
boolean isData = retType == byte[].class;
|
||||||
|
assert isData || retType == SecretKey.class : "Invalid return type.";
|
||||||
|
assert alg != null : "The algorithm cannot be null.";
|
||||||
|
|
||||||
|
long mechanism = isData ? CKM_HKDF_DATA : CKM_HKDF_DERIVE;
|
||||||
|
checkMechanismEnabled(mechanism);
|
||||||
|
|
||||||
|
switch (derivationSpec) {
|
||||||
|
case HKDFParameterSpec.Extract anExtract -> {
|
||||||
|
isExtract = true;
|
||||||
|
baseKey = consolidateKeyMaterial(anExtract.ikms());
|
||||||
|
salt = consolidateKeyMaterial(anExtract.salts());
|
||||||
|
outLen = svcKi.prkLen / 8;
|
||||||
|
assert outLen * 8 == svcKi.prkLen : "Invalid PRK length.";
|
||||||
|
}
|
||||||
|
case HKDFParameterSpec.Expand anExpand -> {
|
||||||
|
isExpand = true;
|
||||||
|
baseKey = anExpand.prk();
|
||||||
|
outLen = anExpand.length();
|
||||||
|
info = anExpand.info();
|
||||||
|
}
|
||||||
|
case HKDFParameterSpec.ExtractThenExpand anExtractExpand -> {
|
||||||
|
isExtract = true;
|
||||||
|
isExpand = true;
|
||||||
|
baseKey = consolidateKeyMaterial(anExtractExpand.ikms());
|
||||||
|
salt = consolidateKeyMaterial(anExtractExpand.salts());
|
||||||
|
outLen = anExtractExpand.length();
|
||||||
|
info = anExtractExpand.info();
|
||||||
|
}
|
||||||
|
case null -> throw new NullPointerException(
|
||||||
|
"derivationSpec must be a " + HKDFParameterSpec.class +
|
||||||
|
" instance, instead of null.");
|
||||||
|
default -> throw new InvalidAlgorithmParameterException(
|
||||||
|
"derivationSpec must be a " + HKDFParameterSpec.class +
|
||||||
|
" instance, instead of " + derivationSpec.getClass());
|
||||||
|
}
|
||||||
|
|
||||||
|
P11Key p11BaseKey = convertKey(baseKey, (isExtract ? "IKM" : "PRK") +
|
||||||
|
" could not be converted to a token key for HKDF derivation.");
|
||||||
|
|
||||||
|
long saltType = CKF_HKDF_SALT_NULL;
|
||||||
|
byte[] saltBytes = null;
|
||||||
|
P11Key p11SaltKey = null;
|
||||||
|
if (salt instanceof SecretKeySpec) {
|
||||||
|
saltType = CKF_HKDF_SALT_DATA;
|
||||||
|
saltBytes = salt.getEncoded();
|
||||||
|
} else if (salt != EMPTY_KEY) {
|
||||||
|
// consolidateKeyMaterial returns a salt from the token.
|
||||||
|
saltType = CKF_HKDF_SALT_KEY;
|
||||||
|
p11SaltKey = (P11Key.P11SecretKey) salt;
|
||||||
|
assert p11SaltKey.token == token : "salt must be from the same " +
|
||||||
|
"token as service.";
|
||||||
|
}
|
||||||
|
|
||||||
|
P11SecretKeyFactory.KeyInfo ki = P11SecretKeyFactory.getKeyInfo(alg);
|
||||||
|
if (ki == null) {
|
||||||
|
throw new InvalidAlgorithmParameterException("A PKCS #11 key " +
|
||||||
|
"type (CKK_*) was not found for a key of the algorithm '" +
|
||||||
|
alg + "'.");
|
||||||
|
}
|
||||||
|
long derivedKeyType = ki.keyType;
|
||||||
|
long derivedKeyClass = isData ? CKO_DATA : CKO_SECRET_KEY;
|
||||||
|
CK_ATTRIBUTE[] attrs = new CK_ATTRIBUTE[] {
|
||||||
|
new CK_ATTRIBUTE(CKA_CLASS, derivedKeyClass),
|
||||||
|
new CK_ATTRIBUTE(CKA_KEY_TYPE, derivedKeyType),
|
||||||
|
new CK_ATTRIBUTE(CKA_VALUE_LEN, outLen)
|
||||||
|
};
|
||||||
|
Session session = null;
|
||||||
|
long baseKeyID = p11BaseKey.getKeyID();
|
||||||
|
try {
|
||||||
|
session = token.getOpSession();
|
||||||
|
CK_HKDF_PARAMS params = new CK_HKDF_PARAMS(isExtract, isExpand,
|
||||||
|
svcKi.hmacMech, saltType, saltBytes, p11SaltKey != null ?
|
||||||
|
p11SaltKey.getKeyID() : 0L, info);
|
||||||
|
attrs = token.getAttributes(O_GENERATE, derivedKeyClass,
|
||||||
|
derivedKeyType, attrs);
|
||||||
|
long derivedObjectID = token.p11.C_DeriveKey(session.id(),
|
||||||
|
new CK_MECHANISM(mechanism, params), baseKeyID, attrs);
|
||||||
|
Object ret;
|
||||||
|
if (isData) {
|
||||||
|
try {
|
||||||
|
CK_ATTRIBUTE[] dataAttr = new CK_ATTRIBUTE[] {
|
||||||
|
new CK_ATTRIBUTE(CKA_VALUE)
|
||||||
|
};
|
||||||
|
token.p11.C_GetAttributeValue(session.id(), derivedObjectID,
|
||||||
|
dataAttr);
|
||||||
|
ret = dataAttr[0].getByteArray();
|
||||||
|
} finally {
|
||||||
|
token.p11.C_DestroyObject(session.id(), derivedObjectID);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
ret = P11Key.secretKey(session, derivedObjectID, alg,
|
||||||
|
outLen * 8, null);
|
||||||
|
}
|
||||||
|
return retType.cast(ret);
|
||||||
|
} catch (PKCS11Exception e) {
|
||||||
|
throw new ProviderException("HKDF derivation for algorithm '" +
|
||||||
|
alg + "' failed.", e);
|
||||||
|
} finally {
|
||||||
|
if (p11SaltKey != null) {
|
||||||
|
p11SaltKey.releaseKeyID();
|
||||||
|
}
|
||||||
|
p11BaseKey.releaseKeyID();
|
||||||
|
token.releaseSession(session);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private P11Key.P11SecretKey convertKey(SecretKey key, String errorMessage) {
|
||||||
|
try {
|
||||||
|
return (P11Key.P11SecretKey) P11SecretKeyFactory.convertKey(token,
|
||||||
|
key, null);
|
||||||
|
} catch (InvalidKeyException ike) {
|
||||||
|
throw new ProviderException(errorMessage, ike);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private abstract sealed class KeyMaterialMerger permits
|
||||||
|
AnyKeyMaterialMerger, KeyKeyMaterialMerger, DataKeyMaterialMerger {
|
||||||
|
|
||||||
|
final KeyMaterialMerger merge(SecretKey nextKeyMaterial) {
|
||||||
|
if (nextKeyMaterial instanceof SecretKeySpec) {
|
||||||
|
return merge(nextKeyMaterial.getEncoded());
|
||||||
|
} else {
|
||||||
|
return merge(convertKey(nextKeyMaterial,
|
||||||
|
"Failure when merging key material."));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
abstract SecretKey getKeyMaterial();
|
||||||
|
|
||||||
|
protected abstract KeyMaterialMerger merge(byte[] nextKeyMaterial);
|
||||||
|
|
||||||
|
protected abstract KeyMaterialMerger merge(
|
||||||
|
P11Key.P11SecretKey nextKeyMaterial);
|
||||||
|
|
||||||
|
protected final P11Key.P11SecretKey p11Merge(
|
||||||
|
P11Key.P11SecretKey baseKey, CK_MECHANISM ckMech,
|
||||||
|
int derivedKeyLen) {
|
||||||
|
checkMechanismEnabled(ckMech.mechanism);
|
||||||
|
Session session = null;
|
||||||
|
long baseKeyID = baseKey.getKeyID();
|
||||||
|
try {
|
||||||
|
session = token.getOpSession();
|
||||||
|
CK_ATTRIBUTE[] attrs = new CK_ATTRIBUTE[] {
|
||||||
|
new CK_ATTRIBUTE(CKA_CLASS, CKO_SECRET_KEY),
|
||||||
|
new CK_ATTRIBUTE(CKA_KEY_TYPE, CKK_GENERIC_SECRET),
|
||||||
|
};
|
||||||
|
long derivedKeyID = token.p11.C_DeriveKey(session.id(), ckMech,
|
||||||
|
baseKeyID, attrs);
|
||||||
|
return (P11Key.P11SecretKey) P11Key.secretKey(session,
|
||||||
|
derivedKeyID, "Generic", derivedKeyLen * 8, null);
|
||||||
|
} catch (PKCS11Exception e) {
|
||||||
|
throw new ProviderException("Failure when merging key " +
|
||||||
|
"material.", e);
|
||||||
|
} finally {
|
||||||
|
baseKey.releaseKeyID();
|
||||||
|
token.releaseSession(session);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private final class AnyKeyMaterialMerger extends KeyMaterialMerger {
|
||||||
|
|
||||||
|
protected KeyMaterialMerger merge(byte[] nextKeyMaterial) {
|
||||||
|
return P11HKDF.this.new DataKeyMaterialMerger(nextKeyMaterial);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected KeyMaterialMerger merge(P11Key.P11SecretKey nextKeyMaterial) {
|
||||||
|
return P11HKDF.this.new KeyKeyMaterialMerger(nextKeyMaterial);
|
||||||
|
}
|
||||||
|
|
||||||
|
SecretKey getKeyMaterial() {
|
||||||
|
return EMPTY_KEY;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private final class KeyKeyMaterialMerger extends KeyMaterialMerger {
|
||||||
|
private P11Key.P11SecretKey keyMaterial;
|
||||||
|
|
||||||
|
KeyKeyMaterialMerger(P11Key.P11SecretKey keyMaterial) {
|
||||||
|
this.keyMaterial = keyMaterial;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected KeyMaterialMerger merge(byte[] nextKeyMaterial) {
|
||||||
|
keyMaterial = p11Merge(keyMaterial,
|
||||||
|
new CK_MECHANISM(CKM_CONCATENATE_BASE_AND_DATA,
|
||||||
|
new CK_KEY_DERIVATION_STRING_DATA(nextKeyMaterial)),
|
||||||
|
keyMaterial.keyLength + nextKeyMaterial.length);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected KeyMaterialMerger merge(P11Key.P11SecretKey nextKeyMaterial) {
|
||||||
|
try {
|
||||||
|
keyMaterial = p11Merge(keyMaterial,
|
||||||
|
new CK_MECHANISM(CKM_CONCATENATE_BASE_AND_KEY,
|
||||||
|
nextKeyMaterial.getKeyID()),
|
||||||
|
keyMaterial.keyLength + nextKeyMaterial.keyLength);
|
||||||
|
} finally {
|
||||||
|
nextKeyMaterial.releaseKeyID();
|
||||||
|
}
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
SecretKey getKeyMaterial() {
|
||||||
|
return keyMaterial;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private final class DataKeyMaterialMerger extends KeyMaterialMerger {
|
||||||
|
private byte[] keyMaterial;
|
||||||
|
|
||||||
|
DataKeyMaterialMerger(byte[] keyMaterial) {
|
||||||
|
this.keyMaterial = keyMaterial;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected KeyMaterialMerger merge(byte[] nextKeyMaterial) {
|
||||||
|
keyMaterial = Arrays.copyOf(keyMaterial,
|
||||||
|
keyMaterial.length + nextKeyMaterial.length);
|
||||||
|
System.arraycopy(nextKeyMaterial, 0, keyMaterial,
|
||||||
|
keyMaterial.length - nextKeyMaterial.length,
|
||||||
|
nextKeyMaterial.length);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected KeyMaterialMerger merge(P11Key.P11SecretKey nextKeyMaterial) {
|
||||||
|
return P11HKDF.this.new KeyKeyMaterialMerger(p11Merge(
|
||||||
|
nextKeyMaterial, new CK_MECHANISM(
|
||||||
|
CKM_CONCATENATE_DATA_AND_BASE,
|
||||||
|
new CK_KEY_DERIVATION_STRING_DATA(keyMaterial)),
|
||||||
|
keyMaterial.length + nextKeyMaterial.keyLength));
|
||||||
|
}
|
||||||
|
|
||||||
|
SecretKey getKeyMaterial() {
|
||||||
|
return new SecretKeySpec(keyMaterial, "Generic");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private SecretKey consolidateKeyMaterial(List<SecretKey> keys) {
|
||||||
|
KeyMaterialMerger keyMerger = P11HKDF.this.new AnyKeyMaterialMerger();
|
||||||
|
for (SecretKey key : keys) {
|
||||||
|
keyMerger = keyMerger.merge(key);
|
||||||
|
}
|
||||||
|
return keyMerger.getKeyMaterial();
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 2003, 2024, Oracle and/or its affiliates. All rights reserved.
|
* Copyright (c) 2003, 2025, Oracle and/or its affiliates. All rights reserved.
|
||||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
*
|
*
|
||||||
* This code is free software; you can redistribute it and/or modify it
|
* This code is free software; you can redistribute it and/or modify it
|
||||||
|
@ -446,7 +446,7 @@ abstract class P11Key implements Key, Length {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static class P11SecretKey extends P11Key implements SecretKey {
|
static class P11SecretKey extends P11Key implements SecretKey {
|
||||||
@Serial
|
@Serial
|
||||||
private static final long serialVersionUID = -7828241727014329084L;
|
private static final long serialVersionUID = -7828241727014329084L;
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 2003, 2023, Oracle and/or its affiliates. All rights reserved.
|
* Copyright (c) 2003, 2025, Oracle and/or its affiliates. All rights reserved.
|
||||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
*
|
*
|
||||||
* This code is free software; you can redistribute it and/or modify it
|
* This code is free software; you can redistribute it and/or modify it
|
||||||
|
@ -90,31 +90,24 @@ final class P11Mac extends MacSpi {
|
||||||
// one byte buffer for the update(byte) method, initialized on demand
|
// one byte buffer for the update(byte) method, initialized on demand
|
||||||
private byte[] oneByte;
|
private byte[] oneByte;
|
||||||
|
|
||||||
P11Mac(Token token, String algorithm, long mechanism)
|
P11Mac(Token token, String algorithm, long mechanism) {
|
||||||
throws PKCS11Exception {
|
|
||||||
super();
|
super();
|
||||||
this.token = token;
|
this.token = token;
|
||||||
this.algorithm = algorithm;
|
this.algorithm = algorithm;
|
||||||
this.svcPbeKi = P11SecretKeyFactory.getPBEKeyInfo(algorithm);
|
this.svcPbeKi = P11SecretKeyFactory.getPBEKeyInfo(algorithm);
|
||||||
Long params = null;
|
if (svcPbeKi != null) {
|
||||||
macLength = switch ((int) mechanism) {
|
macLength = svcPbeKi.keyLen / 8;
|
||||||
case (int) CKM_MD5_HMAC -> 16;
|
} else {
|
||||||
case (int) CKM_SHA_1_HMAC -> 20;
|
P11SecretKeyFactory.HMACKeyInfo svcKi =
|
||||||
case (int) CKM_SHA224_HMAC, (int) CKM_SHA512_224_HMAC, (int) CKM_SHA3_224_HMAC -> 28;
|
P11SecretKeyFactory.getHMACKeyInfo(algorithm);
|
||||||
case (int) CKM_SHA256_HMAC, (int) CKM_SHA512_256_HMAC, (int) CKM_SHA3_256_HMAC -> 32;
|
if (svcKi == null) {
|
||||||
case (int) CKM_SHA384_HMAC, (int) CKM_SHA3_384_HMAC -> 48;
|
throw new ProviderException("Unknown mechanism: " + mechanism);
|
||||||
case (int) CKM_SHA512_HMAC, (int) CKM_SHA3_512_HMAC -> 64;
|
|
||||||
case (int) CKM_SSL3_MD5_MAC -> {
|
|
||||||
params = Long.valueOf(16);
|
|
||||||
yield 16;
|
|
||||||
}
|
}
|
||||||
case (int) CKM_SSL3_SHA1_MAC -> {
|
macLength = svcKi.keyLen / 8;
|
||||||
params = Long.valueOf(20);
|
}
|
||||||
yield 20;
|
ckMechanism = new CK_MECHANISM(mechanism, mechanism == CKM_SSL3_MD5_MAC
|
||||||
}
|
|| mechanism == CKM_SSL3_SHA1_MAC ? Long.valueOf(macLength) :
|
||||||
default -> throw new ProviderException("Unknown mechanism: " + mechanism);
|
null);
|
||||||
};
|
|
||||||
ckMechanism = new CK_MECHANISM(mechanism, params);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// reset the states to the pre-initialized values
|
// reset the states to the pre-initialized values
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 2003, 2024, Oracle and/or its affiliates. All rights reserved.
|
* Copyright (c) 2003, 2025, Oracle and/or its affiliates. All rights reserved.
|
||||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
*
|
*
|
||||||
* This code is free software; you can redistribute it and/or modify it
|
* This code is free software; you can redistribute it and/or modify it
|
||||||
|
@ -67,21 +67,12 @@ final class P11SecretKeyFactory extends SecretKeyFactorySpi {
|
||||||
}
|
}
|
||||||
|
|
||||||
private static final Map<String, KeyInfo> keyInfo = new HashMap<>();
|
private static final Map<String, KeyInfo> keyInfo = new HashMap<>();
|
||||||
private static final KeyInfo HMAC = new KeyInfo("HMAC", PCKK_HMAC);
|
|
||||||
private static final KeyInfo SSLMAC = new KeyInfo("SSLMAC", PCKK_SSLMAC);
|
|
||||||
|
|
||||||
static KeyInfo getKeyInfo(String algo) {
|
static KeyInfo getKeyInfo(String algo) {
|
||||||
KeyInfo ki = keyInfo.get(algo);
|
KeyInfo ki = keyInfo.get(algo);
|
||||||
if (ki == null) {
|
if (ki == null) {
|
||||||
String algoUpper = algo.toUpperCase(Locale.ENGLISH);
|
String algoUpper = algo.toUpperCase(Locale.ENGLISH);
|
||||||
ki = keyInfo.get(algoUpper);
|
ki = keyInfo.get(algoUpper);
|
||||||
if (ki == null) {
|
|
||||||
if (algoUpper.startsWith("HMAC")) {
|
|
||||||
return HMAC;
|
|
||||||
} else if (algoUpper.startsWith("SSLMAC")) {
|
|
||||||
return SSLMAC;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return ki;
|
return ki;
|
||||||
}
|
}
|
||||||
|
@ -93,12 +84,26 @@ final class P11SecretKeyFactory extends SecretKeyFactorySpi {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static HMACKeyInfo getHMACKeyInfo(String algo) {
|
||||||
|
if (getKeyInfo(algo) instanceof HMACKeyInfo hmacKi) {
|
||||||
|
return hmacKi;
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
static HKDFKeyInfo getHKDFKeyInfo(String algo) {
|
||||||
|
if (getKeyInfo(algo) instanceof HKDFKeyInfo hkdfKi) {
|
||||||
|
return hkdfKi;
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
private static void putKeyInfo(KeyInfo ki) {
|
private static void putKeyInfo(KeyInfo ki) {
|
||||||
keyInfo.put(ki.algo, ki);
|
keyInfo.put(ki.algo, ki);
|
||||||
keyInfo.put(ki.algo.toUpperCase(Locale.ENGLISH), ki);
|
keyInfo.put(ki.algo.toUpperCase(Locale.ENGLISH), ki);
|
||||||
}
|
}
|
||||||
|
|
||||||
static sealed class KeyInfo permits PBEKeyInfo {
|
static sealed class KeyInfo permits PBEKeyInfo, HMACKeyInfo, HKDFKeyInfo {
|
||||||
public final String algo;
|
public final String algo;
|
||||||
public final long keyType;
|
public final long keyType;
|
||||||
|
|
||||||
|
@ -129,6 +134,29 @@ final class P11SecretKeyFactory extends SecretKeyFactorySpi {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static final class HMACKeyInfo extends KeyInfo {
|
||||||
|
public final long mech;
|
||||||
|
public final int keyLen;
|
||||||
|
|
||||||
|
HMACKeyInfo(String algo, long mech, int keyLen) {
|
||||||
|
super(algo, CKK_GENERIC_SECRET);
|
||||||
|
this.mech = mech;
|
||||||
|
this.keyLen = keyLen;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static final class HKDFKeyInfo extends KeyInfo {
|
||||||
|
public static final long UNKNOWN_KEY_TYPE = -1;
|
||||||
|
public final long hmacMech;
|
||||||
|
public final int prkLen;
|
||||||
|
|
||||||
|
HKDFKeyInfo(String algo, HMACKeyInfo hmacKi) {
|
||||||
|
super(algo, UNKNOWN_KEY_TYPE);
|
||||||
|
hmacMech = hmacKi.mech;
|
||||||
|
prkLen = hmacKi.keyLen;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
abstract static sealed class PBEKeyInfo extends KeyInfo
|
abstract static sealed class PBEKeyInfo extends KeyInfo
|
||||||
permits AESPBEKeyInfo, PBKDF2KeyInfo, P12MacPBEKeyInfo {
|
permits AESPBEKeyInfo, PBKDF2KeyInfo, P12MacPBEKeyInfo {
|
||||||
public static final long INVALID_PRF = -1;
|
public static final long INVALID_PRF = -1;
|
||||||
|
@ -169,9 +197,9 @@ final class P11SecretKeyFactory extends SecretKeyFactorySpi {
|
||||||
private static final CK_ATTRIBUTE[] attr = new CK_ATTRIBUTE[] {
|
private static final CK_ATTRIBUTE[] attr = new CK_ATTRIBUTE[] {
|
||||||
CK_ATTRIBUTE.SIGN_TRUE};
|
CK_ATTRIBUTE.SIGN_TRUE};
|
||||||
|
|
||||||
P12MacPBEKeyInfo(String algo, long kdfMech, int keyLen) {
|
P12MacPBEKeyInfo(String algo, long kdfMech, HMACKeyInfo hmacKi) {
|
||||||
super(algo, kdfMech, PBEKeyInfo.INVALID_PRF,
|
super(algo, kdfMech, PBEKeyInfo.INVALID_PRF,
|
||||||
CKK_GENERIC_SECRET, keyLen, attr);
|
CKK_GENERIC_SECRET, hmacKi.keyLen, attr);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -195,6 +223,36 @@ final class P11SecretKeyFactory extends SecretKeyFactorySpi {
|
||||||
putKeyInfo(new KeyInfo("TlsMasterSecret", PCKK_TLSMASTER));
|
putKeyInfo(new KeyInfo("TlsMasterSecret", PCKK_TLSMASTER));
|
||||||
putKeyInfo(new KeyInfo("Generic", CKK_GENERIC_SECRET));
|
putKeyInfo(new KeyInfo("Generic", CKK_GENERIC_SECRET));
|
||||||
|
|
||||||
|
HMACKeyInfo hmacSHA1 =
|
||||||
|
new HMACKeyInfo("HmacSHA1", CKM_SHA_1_HMAC, 160);
|
||||||
|
HMACKeyInfo hmacSHA224 =
|
||||||
|
new HMACKeyInfo("HmacSHA224", CKM_SHA224_HMAC, 224);
|
||||||
|
HMACKeyInfo hmacSHA256 =
|
||||||
|
new HMACKeyInfo("HmacSHA256", CKM_SHA256_HMAC, 256);
|
||||||
|
HMACKeyInfo hmacSHA384 =
|
||||||
|
new HMACKeyInfo("HmacSHA384", CKM_SHA384_HMAC, 384);
|
||||||
|
HMACKeyInfo hmacSHA512 =
|
||||||
|
new HMACKeyInfo("HmacSHA512", CKM_SHA512_HMAC, 512);
|
||||||
|
|
||||||
|
putKeyInfo(hmacSHA1);
|
||||||
|
putKeyInfo(hmacSHA224);
|
||||||
|
putKeyInfo(hmacSHA256);
|
||||||
|
putKeyInfo(hmacSHA384);
|
||||||
|
putKeyInfo(hmacSHA512);
|
||||||
|
putKeyInfo(new HMACKeyInfo("HmacMD5", CKM_MD5_HMAC, 128));
|
||||||
|
putKeyInfo(new HMACKeyInfo("HmacSHA512/224", CKM_SHA512_224_HMAC, 224));
|
||||||
|
putKeyInfo(new HMACKeyInfo("HmacSHA3-224", CKM_SHA3_224_HMAC, 224));
|
||||||
|
putKeyInfo(new HMACKeyInfo("HmacSHA512/256", CKM_SHA512_256_HMAC, 256));
|
||||||
|
putKeyInfo(new HMACKeyInfo("HmacSHA3-256", CKM_SHA3_256_HMAC, 256));
|
||||||
|
putKeyInfo(new HMACKeyInfo("HmacSHA3-384", CKM_SHA3_384_HMAC, 384));
|
||||||
|
putKeyInfo(new HMACKeyInfo("HmacSHA3-512", CKM_SHA3_512_HMAC, 512));
|
||||||
|
putKeyInfo(new HMACKeyInfo("SslMacMD5", CKM_SSL3_MD5_MAC, 128));
|
||||||
|
putKeyInfo(new HMACKeyInfo("SslMacSHA1", CKM_SSL3_SHA1_MAC, 160));
|
||||||
|
|
||||||
|
putKeyInfo(new HKDFKeyInfo("HKDF-SHA256", hmacSHA256));
|
||||||
|
putKeyInfo(new HKDFKeyInfo("HKDF-SHA384", hmacSHA384));
|
||||||
|
putKeyInfo(new HKDFKeyInfo("HKDF-SHA512", hmacSHA512));
|
||||||
|
|
||||||
putKeyInfo(new AESPBEKeyInfo("PBEWithHmacSHA1AndAES_128",
|
putKeyInfo(new AESPBEKeyInfo("PBEWithHmacSHA1AndAES_128",
|
||||||
CKP_PKCS5_PBKD2_HMAC_SHA1, 128));
|
CKP_PKCS5_PBKD2_HMAC_SHA1, 128));
|
||||||
putKeyInfo(new AESPBEKeyInfo("PBEWithHmacSHA224AndAES_128",
|
putKeyInfo(new AESPBEKeyInfo("PBEWithHmacSHA224AndAES_128",
|
||||||
|
@ -228,15 +286,15 @@ final class P11SecretKeyFactory extends SecretKeyFactorySpi {
|
||||||
CKP_PKCS5_PBKD2_HMAC_SHA512));
|
CKP_PKCS5_PBKD2_HMAC_SHA512));
|
||||||
|
|
||||||
putKeyInfo(new P12MacPBEKeyInfo("HmacPBESHA1",
|
putKeyInfo(new P12MacPBEKeyInfo("HmacPBESHA1",
|
||||||
CKM_PBA_SHA1_WITH_SHA1_HMAC, 160));
|
CKM_PBA_SHA1_WITH_SHA1_HMAC, hmacSHA1));
|
||||||
putKeyInfo(new P12MacPBEKeyInfo("HmacPBESHA224",
|
putKeyInfo(new P12MacPBEKeyInfo("HmacPBESHA224",
|
||||||
CKM_NSS_PKCS12_PBE_SHA224_HMAC_KEY_GEN, 224));
|
CKM_NSS_PKCS12_PBE_SHA224_HMAC_KEY_GEN, hmacSHA224));
|
||||||
putKeyInfo(new P12MacPBEKeyInfo("HmacPBESHA256",
|
putKeyInfo(new P12MacPBEKeyInfo("HmacPBESHA256",
|
||||||
CKM_NSS_PKCS12_PBE_SHA256_HMAC_KEY_GEN, 256));
|
CKM_NSS_PKCS12_PBE_SHA256_HMAC_KEY_GEN, hmacSHA256));
|
||||||
putKeyInfo(new P12MacPBEKeyInfo("HmacPBESHA384",
|
putKeyInfo(new P12MacPBEKeyInfo("HmacPBESHA384",
|
||||||
CKM_NSS_PKCS12_PBE_SHA384_HMAC_KEY_GEN, 384));
|
CKM_NSS_PKCS12_PBE_SHA384_HMAC_KEY_GEN, hmacSHA384));
|
||||||
putKeyInfo(new P12MacPBEKeyInfo("HmacPBESHA512",
|
putKeyInfo(new P12MacPBEKeyInfo("HmacPBESHA512",
|
||||||
CKM_NSS_PKCS12_PBE_SHA512_HMAC_KEY_GEN, 512));
|
CKM_NSS_PKCS12_PBE_SHA512_HMAC_KEY_GEN, hmacSHA512));
|
||||||
}
|
}
|
||||||
|
|
||||||
// No pseudo key types
|
// No pseudo key types
|
||||||
|
@ -287,8 +345,7 @@ final class P11SecretKeyFactory extends SecretKeyFactorySpi {
|
||||||
}
|
}
|
||||||
// Check if the key can be used for the service.
|
// Check if the key can be used for the service.
|
||||||
// Any key can be used for a MAC service.
|
// Any key can be used for a MAC service.
|
||||||
if (svcAlgo != keyAlgo &&
|
if (svcAlgo != keyAlgo && !(si instanceof HMACKeyInfo)) {
|
||||||
si.keyType != PCKK_HMAC && si.keyType != PCKK_SSLMAC) {
|
|
||||||
ki = getKeyInfo(keyAlgo);
|
ki = getKeyInfo(keyAlgo);
|
||||||
if (ki == null || !KeyInfo.checkUse(ki, si)) {
|
if (ki == null || !KeyInfo.checkUse(ki, si)) {
|
||||||
throw new InvalidKeyException("Cannot use a " + keyAlgo +
|
throw new InvalidKeyException("Cannot use a " + keyAlgo +
|
||||||
|
@ -348,8 +405,7 @@ final class P11SecretKeyFactory extends SecretKeyFactorySpi {
|
||||||
}
|
}
|
||||||
byte[] encoded = key.getEncoded();
|
byte[] encoded = key.getEncoded();
|
||||||
try {
|
try {
|
||||||
p11Key = createKey(token, encoded, svcAlgo, si.keyType,
|
p11Key = createKey(token, encoded, svcAlgo, si, extraAttrs);
|
||||||
extraAttrs);
|
|
||||||
} finally {
|
} finally {
|
||||||
Arrays.fill(encoded, (byte) 0);
|
Arrays.fill(encoded, (byte) 0);
|
||||||
}
|
}
|
||||||
|
@ -486,10 +542,11 @@ final class P11SecretKeyFactory extends SecretKeyFactorySpi {
|
||||||
}
|
}
|
||||||
|
|
||||||
private static P11Key createKey(Token token, byte[] encoded,
|
private static P11Key createKey(Token token, byte[] encoded,
|
||||||
String algorithm, long keyType, CK_ATTRIBUTE[] extraAttrs)
|
String algorithm, KeyInfo ki, CK_ATTRIBUTE[] extraAttrs)
|
||||||
throws InvalidKeyException {
|
throws InvalidKeyException {
|
||||||
int n = encoded.length << 3;
|
int n = encoded.length << 3;
|
||||||
int keyLength = n;
|
int keyLength = n;
|
||||||
|
long keyType = ki.keyType;
|
||||||
try {
|
try {
|
||||||
switch ((int) keyType) {
|
switch ((int) keyType) {
|
||||||
case (int) CKK_DES -> {
|
case (int) CKK_DES -> {
|
||||||
|
@ -520,16 +577,12 @@ final class P11SecretKeyFactory extends SecretKeyFactorySpi {
|
||||||
CKM_CHACHA20_KEY_GEN, n, token);
|
CKM_CHACHA20_KEY_GEN, n, token);
|
||||||
case (int) CKK_GENERIC_SECRET, (int) PCKK_TLSPREMASTER, (int) PCKK_TLSRSAPREMASTER, (int) PCKK_TLSMASTER ->
|
case (int) CKK_GENERIC_SECRET, (int) PCKK_TLSPREMASTER, (int) PCKK_TLSRSAPREMASTER, (int) PCKK_TLSMASTER ->
|
||||||
keyType = CKK_GENERIC_SECRET;
|
keyType = CKK_GENERIC_SECRET;
|
||||||
case (int) PCKK_SSLMAC, (int) PCKK_HMAC -> {
|
|
||||||
if (n == 0) {
|
|
||||||
throw new InvalidKeyException
|
|
||||||
("MAC keys must not be empty");
|
|
||||||
}
|
|
||||||
keyType = CKK_GENERIC_SECRET;
|
|
||||||
}
|
|
||||||
default -> throw new InvalidKeyException("Unknown algorithm " +
|
default -> throw new InvalidKeyException("Unknown algorithm " +
|
||||||
algorithm);
|
algorithm);
|
||||||
}
|
}
|
||||||
|
if (ki instanceof HMACKeyInfo && n == 0) {
|
||||||
|
throw new InvalidKeyException("MAC keys must not be empty");
|
||||||
|
}
|
||||||
} catch (InvalidAlgorithmParameterException iape) {
|
} catch (InvalidAlgorithmParameterException iape) {
|
||||||
throw new InvalidKeyException("Invalid key for " + algorithm,
|
throw new InvalidKeyException("Invalid key for " + algorithm,
|
||||||
iape);
|
iape);
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 2003, 2024, Oracle and/or its affiliates. All rights reserved.
|
* Copyright (c) 2003, 2025, Oracle and/or its affiliates. All rights reserved.
|
||||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
*
|
*
|
||||||
* This code is free software; you can redistribute it and/or modify it
|
* This code is free software; you can redistribute it and/or modify it
|
||||||
|
@ -31,6 +31,7 @@ import java.util.stream.Collectors;
|
||||||
import java.security.*;
|
import java.security.*;
|
||||||
import java.security.interfaces.*;
|
import java.security.interfaces.*;
|
||||||
|
|
||||||
|
import javax.crypto.KDFParameters;
|
||||||
import javax.crypto.interfaces.*;
|
import javax.crypto.interfaces.*;
|
||||||
|
|
||||||
import javax.security.auth.Subject;
|
import javax.security.auth.Subject;
|
||||||
|
@ -526,6 +527,8 @@ public final class SunPKCS11 extends AuthProvider {
|
||||||
|
|
||||||
private static final String SR = "SecureRandom";
|
private static final String SR = "SecureRandom";
|
||||||
|
|
||||||
|
private static final String KDF = "KDF";
|
||||||
|
|
||||||
static {
|
static {
|
||||||
// names of all the implementation classes
|
// names of all the implementation classes
|
||||||
// use local variables, only used here
|
// use local variables, only used here
|
||||||
|
@ -546,6 +549,7 @@ public final class SunPKCS11 extends AuthProvider {
|
||||||
String P11PBECipher = "sun.security.pkcs11.P11PBECipher";
|
String P11PBECipher = "sun.security.pkcs11.P11PBECipher";
|
||||||
String P11Signature = "sun.security.pkcs11.P11Signature";
|
String P11Signature = "sun.security.pkcs11.P11Signature";
|
||||||
String P11PSSSignature = "sun.security.pkcs11.P11PSSSignature";
|
String P11PSSSignature = "sun.security.pkcs11.P11PSSSignature";
|
||||||
|
String P11HKDF = "sun.security.pkcs11.P11HKDF";
|
||||||
|
|
||||||
// XXX register all aliases
|
// XXX register all aliases
|
||||||
|
|
||||||
|
@ -729,6 +733,8 @@ public final class SunPKCS11 extends AuthProvider {
|
||||||
m(CKM_BLOWFISH_CBC));
|
m(CKM_BLOWFISH_CBC));
|
||||||
d(SKF, "ChaCha20", P11SecretKeyFactory,
|
d(SKF, "ChaCha20", P11SecretKeyFactory,
|
||||||
m(CKM_CHACHA20_POLY1305));
|
m(CKM_CHACHA20_POLY1305));
|
||||||
|
d(SKF, "Generic", P11SecretKeyFactory,
|
||||||
|
m(CKM_GENERIC_SECRET_KEY_GEN));
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* PBE Secret Key Factories
|
* PBE Secret Key Factories
|
||||||
|
@ -1073,6 +1079,13 @@ public final class SunPKCS11 extends AuthProvider {
|
||||||
m(CKM_TLS_PRF, CKM_NSS_TLS_PRF_GENERAL));
|
m(CKM_TLS_PRF, CKM_NSS_TLS_PRF_GENERAL));
|
||||||
d(KG, "SunTls12Prf", "sun.security.pkcs11.P11TlsPrfGenerator",
|
d(KG, "SunTls12Prf", "sun.security.pkcs11.P11TlsPrfGenerator",
|
||||||
m(CKM_TLS_MAC));
|
m(CKM_TLS_MAC));
|
||||||
|
|
||||||
|
d(KDF, "HKDF-SHA256", P11HKDF, m(CKM_HKDF_DERIVE, CKM_HKDF_DATA),
|
||||||
|
m(CKM_SHA256_HMAC));
|
||||||
|
d(KDF, "HKDF-SHA384", P11HKDF, m(CKM_HKDF_DERIVE, CKM_HKDF_DATA),
|
||||||
|
m(CKM_SHA384_HMAC));
|
||||||
|
d(KDF, "HKDF-SHA512", P11HKDF, m(CKM_HKDF_DERIVE, CKM_HKDF_DATA),
|
||||||
|
m(CKM_SHA512_HMAC));
|
||||||
}
|
}
|
||||||
|
|
||||||
// background thread that periodically checks for token insertion
|
// background thread that periodically checks for token insertion
|
||||||
|
@ -1507,6 +1520,14 @@ public final class SunPKCS11 extends AuthProvider {
|
||||||
throw new NoSuchAlgorithmException("Unsupported algorithm: "
|
throw new NoSuchAlgorithmException("Unsupported algorithm: "
|
||||||
+ algorithm);
|
+ algorithm);
|
||||||
}
|
}
|
||||||
|
} else if (type == KDF) {
|
||||||
|
try {
|
||||||
|
return new P11HKDF(token, algorithm, (KDFParameters) param);
|
||||||
|
} catch (ClassCastException |
|
||||||
|
InvalidAlgorithmParameterException e) {
|
||||||
|
throw new NoSuchAlgorithmException(
|
||||||
|
"Cannot instantiate a service of KDF type.", e);
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
throw new NoSuchAlgorithmException("Unknown type: " + type);
|
throw new NoSuchAlgorithmException("Unknown type: " + type);
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,174 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2025, Red Hat, Inc.
|
||||||
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
|
*
|
||||||
|
* This code is free software; you can redistribute it and/or modify it
|
||||||
|
* under the terms of the GNU General Public License version 2 only, as
|
||||||
|
* published by the Free Software Foundation. Oracle designates this
|
||||||
|
* particular file as subject to the "Classpath" exception as provided
|
||||||
|
* by Oracle in the LICENSE file that accompanied this code.
|
||||||
|
*
|
||||||
|
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||||
|
* version 2 for more details (a copy is included in the LICENSE file that
|
||||||
|
* accompanied this code).
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License version
|
||||||
|
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||||
|
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||||
|
*
|
||||||
|
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||||
|
* or visit www.oracle.com if you need additional information or have any
|
||||||
|
* questions.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package sun.security.pkcs11.wrapper;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* class CK_HKDF_PARAMS provides the parameters to the CKM_HKDF_DERIVE and
|
||||||
|
* CKM_HKDF_DATA mechanisms.<p>
|
||||||
|
* <b>PKCS#11 structure:</b>
|
||||||
|
* <pre>
|
||||||
|
* typedef struct CK_HKDF_PARAMS {
|
||||||
|
* CK_BBOOL bExtract;
|
||||||
|
* CK_BBOOL bExpand;
|
||||||
|
* CK_MECHANISM_TYPE prfHashMechanism;
|
||||||
|
* CK_ULONG ulSaltType;
|
||||||
|
* CK_BYTE_PTR pSalt;
|
||||||
|
* CK_ULONG ulSaltLen;
|
||||||
|
* CK_OBJECT_HANDLE hSaltKey;
|
||||||
|
* CK_BYTE_PTR pInfo;
|
||||||
|
* CK_ULONG ulInfoLen;
|
||||||
|
* } CK_HKDF_PARAMS;
|
||||||
|
* </pre>
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public class CK_HKDF_PARAMS {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <b>PKCS#11:</b>
|
||||||
|
* <pre>
|
||||||
|
* CK_BBOOL bExtract;
|
||||||
|
* </pre>
|
||||||
|
*/
|
||||||
|
public final boolean bExtract;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <b>PKCS#11:</b>
|
||||||
|
* <pre>
|
||||||
|
* CK_BBOOL bExpand;
|
||||||
|
* </pre>
|
||||||
|
*/
|
||||||
|
public final boolean bExpand;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <b>PKCS#11:</b>
|
||||||
|
* <pre>
|
||||||
|
* CK_MECHANISM_TYPE prfHashMechanism;
|
||||||
|
* </pre>
|
||||||
|
*/
|
||||||
|
public final long prfHashMechanism;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <b>PKCS#11:</b>
|
||||||
|
* <pre>
|
||||||
|
* CK_ULONG ulSaltType;
|
||||||
|
* </pre>
|
||||||
|
*/
|
||||||
|
public final long ulSaltType;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <b>PKCS#11:</b>
|
||||||
|
* <pre>
|
||||||
|
* CK_BYTE_PTR pSalt;
|
||||||
|
* CK_ULONG ulSaltLen;
|
||||||
|
* </pre>
|
||||||
|
*/
|
||||||
|
public final byte[] pSalt;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <b>PKCS#11:</b>
|
||||||
|
* <pre>
|
||||||
|
* CK_OBJECT_HANDLE hSaltKey;
|
||||||
|
* </pre>
|
||||||
|
*/
|
||||||
|
public final long hSaltKey;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <b>PKCS#11:</b>
|
||||||
|
* <pre>
|
||||||
|
* CK_BYTE_PTR pInfo;
|
||||||
|
* CK_ULONG ulInfoLen;
|
||||||
|
* </pre>
|
||||||
|
*/
|
||||||
|
public final byte[] pInfo;
|
||||||
|
|
||||||
|
public CK_HKDF_PARAMS(boolean bExtract, boolean bExpand,
|
||||||
|
long prfHashMechanism, long ulSaltType, byte[] pSalt, long hSaltKey,
|
||||||
|
byte[] pInfo) {
|
||||||
|
this.bExtract = bExtract;
|
||||||
|
this.bExpand = bExpand;
|
||||||
|
this.prfHashMechanism = prfHashMechanism;
|
||||||
|
this.ulSaltType = ulSaltType;
|
||||||
|
this.pSalt = pSalt;
|
||||||
|
this.hSaltKey = hSaltKey;
|
||||||
|
this.pInfo = pInfo;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the string representation of CK_HKDF_PARAMS.
|
||||||
|
*
|
||||||
|
* @return the string representation of CK_HKDF_PARAMS
|
||||||
|
*/
|
||||||
|
public String toString() {
|
||||||
|
StringBuilder sb = new StringBuilder();
|
||||||
|
|
||||||
|
sb.append(Constants.INDENT);
|
||||||
|
sb.append("bExtract: ");
|
||||||
|
sb.append(bExtract);
|
||||||
|
sb.append(Constants.NEWLINE);
|
||||||
|
|
||||||
|
sb.append(Constants.INDENT);
|
||||||
|
sb.append("bExpand: ");
|
||||||
|
sb.append(bExpand);
|
||||||
|
sb.append(Constants.NEWLINE);
|
||||||
|
|
||||||
|
sb.append(Constants.INDENT);
|
||||||
|
sb.append("prfHashMechanism: ");
|
||||||
|
sb.append(Functions.getMechanismName(prfHashMechanism));
|
||||||
|
sb.append(Constants.NEWLINE);
|
||||||
|
|
||||||
|
sb.append(Constants.INDENT);
|
||||||
|
sb.append("ulSaltType: ");
|
||||||
|
sb.append(Functions.saltTypeToString(ulSaltType));
|
||||||
|
sb.append(Constants.NEWLINE);
|
||||||
|
|
||||||
|
sb.append(Constants.INDENT);
|
||||||
|
sb.append("pSalt: ");
|
||||||
|
sb.append(Functions.toHexString(pSalt));
|
||||||
|
sb.append(Constants.NEWLINE);
|
||||||
|
|
||||||
|
sb.append(Constants.INDENT);
|
||||||
|
sb.append("ulSaltLen: ");
|
||||||
|
sb.append(Functions.getLength(pSalt));
|
||||||
|
sb.append(Constants.NEWLINE);
|
||||||
|
|
||||||
|
sb.append(Constants.INDENT);
|
||||||
|
sb.append("hSaltKey: ");
|
||||||
|
sb.append(hSaltKey);
|
||||||
|
sb.append(Constants.NEWLINE);
|
||||||
|
|
||||||
|
sb.append(Constants.INDENT);
|
||||||
|
sb.append("pInfo: ");
|
||||||
|
sb.append(Functions.toHexString(pInfo));
|
||||||
|
sb.append(Constants.NEWLINE);
|
||||||
|
|
||||||
|
sb.append(Constants.INDENT);
|
||||||
|
sb.append("ulInfoLen: ");
|
||||||
|
sb.append(Functions.getLength(pInfo));
|
||||||
|
sb.append(Constants.NEWLINE);
|
||||||
|
|
||||||
|
return sb.toString();
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,79 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2025, Red Hat, Inc.
|
||||||
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
|
*
|
||||||
|
* This code is free software; you can redistribute it and/or modify it
|
||||||
|
* under the terms of the GNU General Public License version 2 only, as
|
||||||
|
* published by the Free Software Foundation. Oracle designates this
|
||||||
|
* particular file as subject to the "Classpath" exception as provided
|
||||||
|
* by Oracle in the LICENSE file that accompanied this code.
|
||||||
|
*
|
||||||
|
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||||
|
* version 2 for more details (a copy is included in the LICENSE file that
|
||||||
|
* accompanied this code).
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License version
|
||||||
|
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||||
|
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||||
|
*
|
||||||
|
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||||
|
* or visit www.oracle.com if you need additional information or have any
|
||||||
|
* questions.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package sun.security.pkcs11.wrapper;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* class CK_KEY_DERIVATION_STRING_DATA provides the parameters to the
|
||||||
|
* CKM_DES_ECB_ENCRYPT_DATA, CKM_DES3_ECB_ENCRYPT_DATA,
|
||||||
|
* CKM_AES_ECB_ENCRYPT_DATA, CKM_CONCATENATE_BASE_AND_DATA,
|
||||||
|
* CKM_CONCATENATE_DATA_AND_BASE, CKM_XOR_BASE_AND_DATA,
|
||||||
|
* CKM_CAMELLIA_ECB_ENCRYPT_DATA, CKM_ARIA_ECB_ENCRYPT_DATA and
|
||||||
|
* CKM_SEED_ECB_ENCRYPT_DATA mechanisms.<p>
|
||||||
|
* <b>PKCS#11 structure:</b>
|
||||||
|
* <pre>
|
||||||
|
* typedef struct CK_KEY_DERIVATION_STRING_DATA {
|
||||||
|
* CK_BYTE_PTR pData;
|
||||||
|
* CK_ULONG ulLen;
|
||||||
|
* } CK_KEY_DERIVATION_STRING_DATA;
|
||||||
|
* </pre>
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public class CK_KEY_DERIVATION_STRING_DATA {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <b>PKCS#11:</b>
|
||||||
|
* <pre>
|
||||||
|
* CK_BYTE_PTR pData;
|
||||||
|
* CK_ULONG ulLen;
|
||||||
|
* </pre>
|
||||||
|
*/
|
||||||
|
public final byte[] pData;
|
||||||
|
|
||||||
|
public CK_KEY_DERIVATION_STRING_DATA(byte[] pData) {
|
||||||
|
this.pData = pData;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the string representation of CK_KEY_DERIVATION_STRING_DATA.
|
||||||
|
*
|
||||||
|
* @return the string representation of CK_KEY_DERIVATION_STRING_DATA
|
||||||
|
*/
|
||||||
|
public String toString() {
|
||||||
|
StringBuilder sb = new StringBuilder();
|
||||||
|
|
||||||
|
sb.append(Constants.INDENT);
|
||||||
|
sb.append("pData: ");
|
||||||
|
sb.append(Functions.toHexString(pData));
|
||||||
|
sb.append(Constants.NEWLINE);
|
||||||
|
|
||||||
|
sb.append(Constants.INDENT);
|
||||||
|
sb.append("ulLen: ");
|
||||||
|
sb.append(Functions.getLength(pData));
|
||||||
|
sb.append(Constants.NEWLINE);
|
||||||
|
|
||||||
|
return sb.toString();
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 2003, 2024, Oracle and/or its affiliates. All rights reserved.
|
* Copyright (c) 2003, 2025, Oracle and/or its affiliates. All rights reserved.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/* Copyright (c) 2002 Graz University of Technology. All rights reserved.
|
/* Copyright (c) 2002 Graz University of Technology. All rights reserved.
|
||||||
|
@ -127,6 +127,14 @@ public class CK_MECHANISM {
|
||||||
init(mechanism, params);
|
init(mechanism, params);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public CK_MECHANISM(long mechanism, CK_HKDF_PARAMS params) {
|
||||||
|
init(mechanism, params);
|
||||||
|
}
|
||||||
|
|
||||||
|
public CK_MECHANISM(long mechanism, CK_KEY_DERIVATION_STRING_DATA params) {
|
||||||
|
init(mechanism, params);
|
||||||
|
}
|
||||||
|
|
||||||
public CK_MECHANISM(long mechanism, CK_ECDH1_DERIVE_PARAMS params) {
|
public CK_MECHANISM(long mechanism, CK_ECDH1_DERIVE_PARAMS params) {
|
||||||
init(mechanism, params);
|
init(mechanism, params);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 2003, 2023, Oracle and/or its affiliates. All rights reserved.
|
* Copyright (c) 2003, 2025, Oracle and/or its affiliates. All rights reserved.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/* Copyright (c) 2002 Graz University of Technology. All rights reserved.
|
/* Copyright (c) 2002 Graz University of Technology. All rights reserved.
|
||||||
|
@ -440,6 +440,26 @@ public class Functions {
|
||||||
return mechanismInfoFlags.toString(flags);
|
return mechanismInfoFlags.toString(flags);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static final Flags hkdfSaltTypes = new Flags(new long[] {
|
||||||
|
CKF_HKDF_SALT_NULL,
|
||||||
|
CKF_HKDF_SALT_DATA,
|
||||||
|
CKF_HKDF_SALT_KEY
|
||||||
|
}, new String[] {
|
||||||
|
"CKF_HKDF_SALT_NULL",
|
||||||
|
"CKF_HKDF_SALT_DATA",
|
||||||
|
"CKF_HKDF_SALT_KEY"
|
||||||
|
});
|
||||||
|
|
||||||
|
/**
|
||||||
|
* converts a long value to a HKDF salt type string
|
||||||
|
*
|
||||||
|
* @param ulSaltType the HKDF salt type to be converted
|
||||||
|
* @return the HKDF salt type string representation
|
||||||
|
*/
|
||||||
|
public static String saltTypeToString(long ulSaltType) {
|
||||||
|
return hkdfSaltTypes.toString(ulSaltType);
|
||||||
|
}
|
||||||
|
|
||||||
private static String getName(Map<Integer,String> nameMap, long id) {
|
private static String getName(Map<Integer,String> nameMap, long id) {
|
||||||
String name = null;
|
String name = null;
|
||||||
if ((id >>> 32) == 0) {
|
if ((id >>> 32) == 0) {
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 2003, 2023, Oracle and/or its affiliates. All rights reserved.
|
* Copyright (c) 2003, 2025, Oracle and/or its affiliates. All rights reserved.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/* Copyright (c) 2002 Graz University of Technology. All rights reserved.
|
/* Copyright (c) 2002 Graz University of Technology. All rights reserved.
|
||||||
|
@ -311,8 +311,6 @@ public interface PKCS11Constants {
|
||||||
// pseudo key type ANY (for template manager)
|
// pseudo key type ANY (for template manager)
|
||||||
public static final long PCKK_ANY = 0x7FFFFF22L;
|
public static final long PCKK_ANY = 0x7FFFFF22L;
|
||||||
|
|
||||||
public static final long PCKK_HMAC = 0x7FFFFF23L;
|
|
||||||
public static final long PCKK_SSLMAC = 0x7FFFFF24L;
|
|
||||||
public static final long PCKK_TLSPREMASTER = 0x7FFFFF25L;
|
public static final long PCKK_TLSPREMASTER = 0x7FFFFF25L;
|
||||||
public static final long PCKK_TLSRSAPREMASTER = 0x7FFFFF26L;
|
public static final long PCKK_TLSRSAPREMASTER = 0x7FFFFF26L;
|
||||||
public static final long PCKK_TLSMASTER = 0x7FFFFF27L;
|
public static final long PCKK_TLSMASTER = 0x7FFFFF27L;
|
||||||
|
@ -1156,11 +1154,11 @@ public interface PKCS11Constants {
|
||||||
= 0x00000001L;
|
= 0x00000001L;
|
||||||
public static final long CK_SP800_108_DKM_LENGTH_SUM_OF_SEGMENTS
|
public static final long CK_SP800_108_DKM_LENGTH_SUM_OF_SEGMENTS
|
||||||
= 0x00000002L;
|
= 0x00000002L;
|
||||||
|
*/
|
||||||
|
|
||||||
public static final long CKF_HKDF_SALT_NULL = 0x00000001L;
|
public static final long CKF_HKDF_SALT_NULL = 0x00000001L;
|
||||||
public static final long CKF_HKDF_SALT_DATA = 0x00000002L;
|
public static final long CKF_HKDF_SALT_DATA = 0x00000002L;
|
||||||
public static final long CKF_HKDF_SALT_KEY = 0x00000004L;
|
public static final long CKF_HKDF_SALT_KEY = 0x00000004L;
|
||||||
*/
|
|
||||||
|
|
||||||
// private NSS attribute (for DSA and DH private keys)
|
// private NSS attribute (for DSA and DH private keys)
|
||||||
public static final long CKA_NETSCAPE_DB = 0xD5A0DB00L;
|
public static final long CKA_NETSCAPE_DB = 0xD5A0DB00L;
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 2003, 2024, Oracle and/or its affiliates. All rights reserved.
|
* Copyright (c) 2003, 2025, Oracle and/or its affiliates. All rights reserved.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/* Copyright (c) 2002 Graz University of Technology. All rights reserved.
|
/* Copyright (c) 2002 Graz University of Technology. All rights reserved.
|
||||||
|
@ -731,6 +731,150 @@ jTlsMacParamsToCKTlsMacParamPtr(JNIEnv *env, jobject jParam, CK_ULONG *pLength)
|
||||||
return ckParamPtr;
|
return ckParamPtr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* converts a Java CK_HKDF_PARAMS object to a CK_HKDF_PARAMS pointer
|
||||||
|
*
|
||||||
|
* @param env - used to call JNI functions to get Java classes and objects
|
||||||
|
* @param jParam - a Java CK_HKDF_PARAMS object to convert
|
||||||
|
* @param pLength - length of the allocated memory of the returned pointer
|
||||||
|
* @return pointer to a new CK_HKDF_PARAMS structure
|
||||||
|
*/
|
||||||
|
CK_HKDF_PARAMS_PTR
|
||||||
|
jHkdfParamsToCKHkdfParamsPtr(JNIEnv *env, jobject jParam, CK_ULONG* pLength)
|
||||||
|
{
|
||||||
|
CK_HKDF_PARAMS_PTR ckParamPtr = NULL;
|
||||||
|
jclass jHkdfParamsClass;
|
||||||
|
jfieldID fieldID;
|
||||||
|
jboolean jbExtract, jbExpand;
|
||||||
|
jlong jPrfHashMechanism, julSaltType, jhSaltKey;
|
||||||
|
jobject jpSalt, jpInfo;
|
||||||
|
|
||||||
|
if (pLength != NULL) {
|
||||||
|
*pLength = 0L;
|
||||||
|
}
|
||||||
|
|
||||||
|
jHkdfParamsClass = (*env)->FindClass(env, CLASS_HKDF_PARAMS);
|
||||||
|
if (jHkdfParamsClass == NULL) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
fieldID = (*env)->GetFieldID(env, jHkdfParamsClass, "bExtract", "Z");
|
||||||
|
if (fieldID == NULL) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
jbExtract = (*env)->GetBooleanField(env, jParam, fieldID);
|
||||||
|
fieldID = (*env)->GetFieldID(env, jHkdfParamsClass, "bExpand", "Z");
|
||||||
|
if (fieldID == NULL) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
jbExpand = (*env)->GetBooleanField(env, jParam, fieldID);
|
||||||
|
fieldID = (*env)->GetFieldID(env, jHkdfParamsClass, "prfHashMechanism", "J");
|
||||||
|
if (fieldID == NULL) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
jPrfHashMechanism = (*env)->GetLongField(env, jParam, fieldID);
|
||||||
|
fieldID = (*env)->GetFieldID(env, jHkdfParamsClass, "ulSaltType", "J");
|
||||||
|
if (fieldID == NULL) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
julSaltType = (*env)->GetLongField(env, jParam, fieldID);
|
||||||
|
fieldID = (*env)->GetFieldID(env, jHkdfParamsClass, "pSalt", "[B");
|
||||||
|
if (fieldID == NULL) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
jpSalt = (*env)->GetObjectField(env, jParam, fieldID);
|
||||||
|
fieldID = (*env)->GetFieldID(env, jHkdfParamsClass, "hSaltKey", "J");
|
||||||
|
if (fieldID == NULL) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
jhSaltKey = (*env)->GetLongField(env, jParam, fieldID);
|
||||||
|
fieldID = (*env)->GetFieldID(env, jHkdfParamsClass, "pInfo", "[B");
|
||||||
|
if (fieldID == NULL) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
jpInfo = (*env)->GetObjectField(env, jParam, fieldID);
|
||||||
|
|
||||||
|
ckParamPtr = calloc(1, sizeof(CK_HKDF_PARAMS));
|
||||||
|
if (ckParamPtr == NULL) {
|
||||||
|
p11ThrowOutOfMemoryError(env, 0);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
ckParamPtr->bExtract = jBooleanToCKBBool(jbExtract);
|
||||||
|
ckParamPtr->bExpand = jBooleanToCKBBool(jbExpand);
|
||||||
|
ckParamPtr->prfHashMechanism = jLongToCKULong(jPrfHashMechanism);
|
||||||
|
ckParamPtr->ulSaltType = jLongToCKULong(julSaltType);
|
||||||
|
jByteArrayToCKByteArray(env, jpSalt, &(ckParamPtr->pSalt), &(ckParamPtr->ulSaltLen));
|
||||||
|
if ((*env)->ExceptionCheck(env)) {
|
||||||
|
goto cleanup;
|
||||||
|
}
|
||||||
|
ckParamPtr->hSaltKey = jLongToCKULong(jhSaltKey);
|
||||||
|
jByteArrayToCKByteArray(env, jpInfo, &(ckParamPtr->pInfo), &(ckParamPtr->ulInfoLen));
|
||||||
|
if ((*env)->ExceptionCheck(env)) {
|
||||||
|
goto cleanup;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pLength != NULL) {
|
||||||
|
*pLength = sizeof(CK_HKDF_PARAMS);
|
||||||
|
}
|
||||||
|
return ckParamPtr;
|
||||||
|
cleanup:
|
||||||
|
free(ckParamPtr->pInfo);
|
||||||
|
free(ckParamPtr->pSalt);
|
||||||
|
free(ckParamPtr);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* converts a Java CK_KEY_DERIVATION_STRING_DATA object to a CK_KEY_DERIVATION_STRING_DATA pointer
|
||||||
|
*
|
||||||
|
* @param env - used to call JNI functions to get Java classes and objects
|
||||||
|
* @param jParam - a Java CK_KEY_DERIVATION_STRING_DATA object to convert
|
||||||
|
* @param pLength - length of the allocated memory of the returned pointer
|
||||||
|
* @return pointer to a new CK_KEY_DERIVATION_STRING_DATA structure
|
||||||
|
*/
|
||||||
|
CK_KEY_DERIVATION_STRING_DATA_PTR
|
||||||
|
jKeyDerivationStringDataToCKKeyDerivationStringDataPtr(JNIEnv *env, jobject jParam, CK_ULONG *pLength)
|
||||||
|
{
|
||||||
|
CK_KEY_DERIVATION_STRING_DATA_PTR ckParamPtr = NULL;
|
||||||
|
jclass jKeyDerivationStringDataClass;
|
||||||
|
jfieldID fieldID;
|
||||||
|
jobject jpData;
|
||||||
|
|
||||||
|
if (pLength != NULL) {
|
||||||
|
*pLength = 0L;
|
||||||
|
}
|
||||||
|
|
||||||
|
jKeyDerivationStringDataClass = (*env)->FindClass(env, CLASS_KEY_DERIVATION_STRING_DATA);
|
||||||
|
if (jKeyDerivationStringDataClass == NULL) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
fieldID = (*env)->GetFieldID(env, jKeyDerivationStringDataClass, "pData", "[B");
|
||||||
|
if (fieldID == NULL) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
jpData = (*env)->GetObjectField(env, jParam, fieldID);
|
||||||
|
|
||||||
|
ckParamPtr = calloc(1, sizeof(CK_KEY_DERIVATION_STRING_DATA));
|
||||||
|
if (ckParamPtr == NULL) {
|
||||||
|
p11ThrowOutOfMemoryError(env, 0);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
jByteArrayToCKByteArray(env, jpData, &(ckParamPtr->pData), &(ckParamPtr->ulLen));
|
||||||
|
if ((*env)->ExceptionCheck(env)) {
|
||||||
|
goto cleanup;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pLength != NULL) {
|
||||||
|
*pLength = sizeof(CK_KEY_DERIVATION_STRING_DATA);
|
||||||
|
}
|
||||||
|
return ckParamPtr;
|
||||||
|
cleanup:
|
||||||
|
free(ckParamPtr->pData);
|
||||||
|
free(ckParamPtr);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
void keyMatParamToCKKeyMatParam(JNIEnv *env, jobject jParam,
|
void keyMatParamToCKKeyMatParam(JNIEnv *env, jobject jParam,
|
||||||
jclass jKeyMatParamClass,
|
jclass jKeyMatParamClass,
|
||||||
CK_ULONG* cKKeyMatParamUlMacSizeInBits,
|
CK_ULONG* cKKeyMatParamUlMacSizeInBits,
|
||||||
|
@ -1497,6 +1641,15 @@ CK_VOID_PTR jMechParamToCKMechParamPtrSlow(JNIEnv *env, jobject jParam,
|
||||||
ckpParamPtr = jTlsMacParamsToCKTlsMacParamPtr(env, jParam,
|
ckpParamPtr = jTlsMacParamsToCKTlsMacParamPtr(env, jParam,
|
||||||
ckpLength);
|
ckpLength);
|
||||||
break;
|
break;
|
||||||
|
case CKM_HKDF_DATA:
|
||||||
|
case CKM_HKDF_DERIVE:
|
||||||
|
ckpParamPtr = jHkdfParamsToCKHkdfParamsPtr(env, jParam, ckpLength);
|
||||||
|
break;
|
||||||
|
case CKM_CONCATENATE_BASE_AND_DATA:
|
||||||
|
case CKM_CONCATENATE_DATA_AND_BASE:
|
||||||
|
ckpParamPtr = jKeyDerivationStringDataToCKKeyDerivationStringDataPtr(env, jParam,
|
||||||
|
ckpLength);
|
||||||
|
break;
|
||||||
case CKM_AES_CTR:
|
case CKM_AES_CTR:
|
||||||
ckpParamPtr = jAesCtrParamsToCKAesCtrParamPtr(env, jParam,
|
ckpParamPtr = jAesCtrParamsToCKAesCtrParamPtr(env, jParam,
|
||||||
ckpLength);
|
ckpLength);
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 2003, 2024, Oracle and/or its affiliates. All rights reserved.
|
* Copyright (c) 2003, 2025, Oracle and/or its affiliates. All rights reserved.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/* Copyright (c) 2002 Graz University of Technology. All rights reserved.
|
/* Copyright (c) 2002 Graz University of Technology. All rights reserved.
|
||||||
|
@ -355,6 +355,16 @@ void freeCKMechanismPtr(CK_MECHANISM_PTR mechPtr) {
|
||||||
free(((CK_TLS_PRF_PARAMS*)tmp)->pulOutputLen);
|
free(((CK_TLS_PRF_PARAMS*)tmp)->pulOutputLen);
|
||||||
free(((CK_TLS_PRF_PARAMS*)tmp)->pOutput);
|
free(((CK_TLS_PRF_PARAMS*)tmp)->pOutput);
|
||||||
break;
|
break;
|
||||||
|
case CKM_HKDF_DERIVE:
|
||||||
|
TRACE0("[ CK_HKDF_PARAMS ]\n");
|
||||||
|
free(((CK_HKDF_PARAMS*)tmp)->pSalt);
|
||||||
|
free(((CK_HKDF_PARAMS*)tmp)->pInfo);
|
||||||
|
break;
|
||||||
|
case CKM_CONCATENATE_BASE_AND_DATA:
|
||||||
|
case CKM_CONCATENATE_DATA_AND_BASE:
|
||||||
|
TRACE0("[ CK_KEY_DERIVATION_STRING_DATA ]\n");
|
||||||
|
free(((CK_KEY_DERIVATION_STRING_DATA*)tmp)->pData);
|
||||||
|
break;
|
||||||
case CKM_SSL3_MASTER_KEY_DERIVE:
|
case CKM_SSL3_MASTER_KEY_DERIVE:
|
||||||
case CKM_TLS_MASTER_KEY_DERIVE:
|
case CKM_TLS_MASTER_KEY_DERIVE:
|
||||||
case CKM_SSL3_MASTER_KEY_DERIVE_DH:
|
case CKM_SSL3_MASTER_KEY_DERIVE_DH:
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 2003, 2024, Oracle and/or its affiliates. All rights reserved.
|
* Copyright (c) 2003, 2025, Oracle and/or its affiliates. All rights reserved.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/* Copyright (c) 2002 Graz University of Technology. All rights reserved.
|
/* Copyright (c) 2002 Graz University of Technology. All rights reserved.
|
||||||
|
@ -297,9 +297,9 @@ void printDebug(const char *format, ...);
|
||||||
#define CLASS_SKIPJACK_PRIVATE_WRAP_PARAMS "sun/security/pkcs11/wrapper/CK_SKIPJACK_PRIVATE_WRAP_PARAMS"
|
#define CLASS_SKIPJACK_PRIVATE_WRAP_PARAMS "sun/security/pkcs11/wrapper/CK_SKIPJACK_PRIVATE_WRAP_PARAMS"
|
||||||
#define CLASS_SKIPJACK_RELAYX_PARAMS "sun/security/pkcs11/wrapper/CK_SKIPJACK_RELAYX_PARAMS"
|
#define CLASS_SKIPJACK_RELAYX_PARAMS "sun/security/pkcs11/wrapper/CK_SKIPJACK_RELAYX_PARAMS"
|
||||||
#define CLASS_KEY_WRAP_SET_OAEP_PARAMS "sun/security/pkcs11/wrapper/CK_KEY_WRAP_SET_OAEP_PARAMS"
|
#define CLASS_KEY_WRAP_SET_OAEP_PARAMS "sun/security/pkcs11/wrapper/CK_KEY_WRAP_SET_OAEP_PARAMS"
|
||||||
#define CLASS_KEY_DERIVATION_STRING_DATA "sun/security/pkcs11/wrapper/CK_KEY_DERIVATION_STRING_DATA"
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#define CLASS_KEY_DERIVATION_STRING_DATA "sun/security/pkcs11/wrapper/CK_KEY_DERIVATION_STRING_DATA"
|
||||||
#define CLASS_SSL3_RANDOM_DATA "sun/security/pkcs11/wrapper/CK_SSL3_RANDOM_DATA"
|
#define CLASS_SSL3_RANDOM_DATA "sun/security/pkcs11/wrapper/CK_SSL3_RANDOM_DATA"
|
||||||
// CLASS_SSL3_RANDOM_DATA is used by CLASS_SSL3_MASTER_KEY_DERIVE_PARAMS
|
// CLASS_SSL3_RANDOM_DATA is used by CLASS_SSL3_MASTER_KEY_DERIVE_PARAMS
|
||||||
#define CLASS_SSL3_KEY_MAT_OUT "sun/security/pkcs11/wrapper/CK_SSL3_KEY_MAT_OUT"
|
#define CLASS_SSL3_KEY_MAT_OUT "sun/security/pkcs11/wrapper/CK_SSL3_KEY_MAT_OUT"
|
||||||
|
@ -310,6 +310,7 @@ void printDebug(const char *format, ...);
|
||||||
#define CLASS_TLS12_KEY_MAT_PARAMS "sun/security/pkcs11/wrapper/CK_TLS12_KEY_MAT_PARAMS"
|
#define CLASS_TLS12_KEY_MAT_PARAMS "sun/security/pkcs11/wrapper/CK_TLS12_KEY_MAT_PARAMS"
|
||||||
#define CLASS_TLS_PRF_PARAMS "sun/security/pkcs11/wrapper/CK_TLS_PRF_PARAMS"
|
#define CLASS_TLS_PRF_PARAMS "sun/security/pkcs11/wrapper/CK_TLS_PRF_PARAMS"
|
||||||
#define CLASS_TLS_MAC_PARAMS "sun/security/pkcs11/wrapper/CK_TLS_MAC_PARAMS"
|
#define CLASS_TLS_MAC_PARAMS "sun/security/pkcs11/wrapper/CK_TLS_MAC_PARAMS"
|
||||||
|
#define CLASS_HKDF_PARAMS "sun/security/pkcs11/wrapper/CK_HKDF_PARAMS"
|
||||||
|
|
||||||
/* function to update the CK_NSS_GCM_PARAMS in mechanism pointer with
|
/* function to update the CK_NSS_GCM_PARAMS in mechanism pointer with
|
||||||
* CK_GCM_PARAMS
|
* CK_GCM_PARAMS
|
||||||
|
@ -394,7 +395,8 @@ CK_PBE_PARAMS_PTR jPbeParamToCKPbeParamPtr(JNIEnv *env, jobject jParam, CK_ULONG
|
||||||
CK_VOID_PTR jPkcs5Pbkd2ParamToCKPkcs5Pbkd2ParamPtr(JNIEnv *env, jobject jParam, CK_ULONG* pLength);
|
CK_VOID_PTR jPkcs5Pbkd2ParamToCKPkcs5Pbkd2ParamPtr(JNIEnv *env, jobject jParam, CK_ULONG* pLength);
|
||||||
CK_SSL3_MASTER_KEY_DERIVE_PARAMS_PTR jSsl3MasterKeyDeriveParamToCKSsl3MasterKeyDeriveParamPtr(JNIEnv *env, jobject jParam, CK_ULONG* pLength);
|
CK_SSL3_MASTER_KEY_DERIVE_PARAMS_PTR jSsl3MasterKeyDeriveParamToCKSsl3MasterKeyDeriveParamPtr(JNIEnv *env, jobject jParam, CK_ULONG* pLength);
|
||||||
CK_SSL3_KEY_MAT_PARAMS_PTR jSsl3KeyMatParamToCKSsl3KeyMatParamPtr(JNIEnv *env, jobject jParam, CK_ULONG* pLength);
|
CK_SSL3_KEY_MAT_PARAMS_PTR jSsl3KeyMatParamToCKSsl3KeyMatParamPtr(JNIEnv *env, jobject jParam, CK_ULONG* pLength);
|
||||||
CK_KEY_DERIVATION_STRING_DATA jKeyDerivationStringDataToCKKeyDerivationStringData(JNIEnv *env, jobject jParam);
|
CK_HKDF_PARAMS_PTR jHkdfParamsToCKHkdfParamsPtr(JNIEnv *env, jobject jParam, CK_ULONG* pLength);
|
||||||
|
CK_KEY_DERIVATION_STRING_DATA_PTR jKeyDerivationStringDataToCKKeyDerivationStringDataPtr(JNIEnv *env, jobject jParam, CK_ULONG* pLength);
|
||||||
CK_RSA_PKCS_PSS_PARAMS_PTR jRsaPkcsPssParamToCKRsaPkcsPssParamPtr(JNIEnv *env, jobject jParam, CK_ULONG* pLength);
|
CK_RSA_PKCS_PSS_PARAMS_PTR jRsaPkcsPssParamToCKRsaPkcsPssParamPtr(JNIEnv *env, jobject jParam, CK_ULONG* pLength);
|
||||||
CK_ECDH1_DERIVE_PARAMS_PTR jEcdh1DeriveParamToCKEcdh1DeriveParamPtr(JNIEnv *env, jobject jParam, CK_ULONG* pLength);
|
CK_ECDH1_DERIVE_PARAMS_PTR jEcdh1DeriveParamToCKEcdh1DeriveParamPtr(JNIEnv *env, jobject jParam, CK_ULONG* pLength);
|
||||||
CK_ECDH2_DERIVE_PARAMS_PTR jEcdh2DeriveParamToCKEcdh2DeriveParamPtr(JNIEnv *env, jobject jParam, CK_ULONG* pLength);
|
CK_ECDH2_DERIVE_PARAMS_PTR jEcdh2DeriveParamToCKEcdh2DeriveParamPtr(JNIEnv *env, jobject jParam, CK_ULONG* pLength);
|
||||||
|
|
634
test/jdk/sun/security/pkcs11/KDF/TestHKDF.java
Normal file
634
test/jdk/sun/security/pkcs11/KDF/TestHKDF.java
Normal file
|
@ -0,0 +1,634 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2025, Red Hat, Inc.
|
||||||
|
*
|
||||||
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
|
*
|
||||||
|
* This code is free software; you can redistribute it and/or modify it
|
||||||
|
* under the terms of the GNU General Public License version 2 only, as
|
||||||
|
* published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||||
|
* version 2 for more details (a copy is included in the LICENSE file that
|
||||||
|
* accompanied this code).
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License version
|
||||||
|
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||||
|
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||||
|
*
|
||||||
|
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||||
|
* or visit www.oracle.com if you need additional information or have any
|
||||||
|
* questions.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import javax.crypto.*;
|
||||||
|
import javax.crypto.spec.*;
|
||||||
|
import java.io.ByteArrayOutputStream;
|
||||||
|
import java.io.OutputStream;
|
||||||
|
import java.io.PrintWriter;
|
||||||
|
import java.lang.reflect.Method;
|
||||||
|
import java.math.BigInteger;
|
||||||
|
import java.security.*;
|
||||||
|
import java.security.spec.*;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.function.Consumer;
|
||||||
|
import java.util.function.Supplier;
|
||||||
|
import java.util.HexFormat;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* @test
|
||||||
|
* @bug 8328119
|
||||||
|
* @summary test HKDF key derivation in SunPKCS11
|
||||||
|
* @library /test/lib ..
|
||||||
|
* @enablePreview
|
||||||
|
* @run main/othervm/timeout=30 TestHKDF
|
||||||
|
*/
|
||||||
|
|
||||||
|
public final class TestHKDF extends PKCS11Test {
|
||||||
|
|
||||||
|
private static final boolean DEBUG = false;
|
||||||
|
private static final HexFormat hex = HexFormat.of().withLowerCase();
|
||||||
|
private static final byte[] knownBytes = hex.parseHex(
|
||||||
|
"000102030405060708090a0b0c0d0e0f10111213141516");
|
||||||
|
private static final OutputStream debugOut = new ByteArrayOutputStream();
|
||||||
|
private static final PrintWriter debugPrinter = new PrintWriter(debugOut);
|
||||||
|
private static boolean testFailed = false;
|
||||||
|
private static Provider p11Provider;
|
||||||
|
private static SecretKeyFactory p11GenericSkf;
|
||||||
|
|
||||||
|
private record TestContext(String hkdfAlg, String derivedKeyAlg,
|
||||||
|
Supplier<SecretKey> baseKey, byte[] salt, byte[] info,
|
||||||
|
byte[] expectedPRK, byte[] expectedOKM, byte[] expectedOpOut) {
|
||||||
|
// expectedOpOut value:
|
||||||
|
// - If derivedKeyAlg is AES, expectedOpOut is the result of encrypting
|
||||||
|
// knownBytes with derivedKey, using AES/CBC/PKCS5Padding and an IV
|
||||||
|
// of 16 zero bytes.
|
||||||
|
// - If derivedKeyAlg is Generic, expectedOpOut is the result of
|
||||||
|
// calculating the HmacSHA256 of knownBytes with derivedKey.
|
||||||
|
}
|
||||||
|
|
||||||
|
private static class HkdfTestAssertionException extends Exception {
|
||||||
|
HkdfTestAssertionException(String msg) {
|
||||||
|
super(msg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private enum KdfParamSpecType {
|
||||||
|
EXTRACT,
|
||||||
|
EXPAND,
|
||||||
|
EXTRACT_EXPAND
|
||||||
|
}
|
||||||
|
|
||||||
|
private enum KeyMaterialType {
|
||||||
|
KEY,
|
||||||
|
DATA
|
||||||
|
}
|
||||||
|
|
||||||
|
private static final List<List<KeyMaterialType>> keyMaterialCombinations =
|
||||||
|
List.of(
|
||||||
|
List.of(KeyMaterialType.KEY),
|
||||||
|
List.of(KeyMaterialType.DATA),
|
||||||
|
List.of(KeyMaterialType.KEY, KeyMaterialType.KEY),
|
||||||
|
List.of(KeyMaterialType.KEY, KeyMaterialType.DATA),
|
||||||
|
List.of(KeyMaterialType.DATA, KeyMaterialType.KEY),
|
||||||
|
List.of(KeyMaterialType.DATA, KeyMaterialType.DATA)
|
||||||
|
);
|
||||||
|
|
||||||
|
private static void addKeyMaterial(
|
||||||
|
List<KeyMaterialType> keyMaterialCombination, byte[] keyMaterial,
|
||||||
|
Consumer<SecretKey> addKeyCb, Consumer<byte[]> addDataCb)
|
||||||
|
throws Exception {
|
||||||
|
if (keyMaterial.length < keyMaterialCombination.size()) {
|
||||||
|
throw new Exception("Key material is not enough to fulfill the " +
|
||||||
|
"combination requirement.");
|
||||||
|
}
|
||||||
|
int dataStart = 0, dataEnd;
|
||||||
|
for (int i = 0; i < keyMaterialCombination.size(); i++) {
|
||||||
|
dataEnd =
|
||||||
|
keyMaterial.length - keyMaterialCombination.size() + i + 1;
|
||||||
|
byte[] chunk = Arrays.copyOfRange(keyMaterial, dataStart, dataEnd);
|
||||||
|
if (keyMaterialCombination.get(i) == KeyMaterialType.KEY) {
|
||||||
|
addKeyCb.accept(p11GenericSkf.generateSecret(
|
||||||
|
new SecretKeySpec(chunk, "Generic")));
|
||||||
|
} else {
|
||||||
|
addDataCb.accept(chunk);
|
||||||
|
}
|
||||||
|
dataStart = dataEnd;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static List<AlgorithmParameterSpec> generateKdfParamSpecs(
|
||||||
|
TestContext ctx, KdfParamSpecType type) throws Exception {
|
||||||
|
List<AlgorithmParameterSpec> kdfParamSpecs = new ArrayList<>();
|
||||||
|
if (type == KdfParamSpecType.EXTRACT ||
|
||||||
|
type == KdfParamSpecType.EXTRACT_EXPAND) {
|
||||||
|
for (List<KeyMaterialType> keyMaterialCombination :
|
||||||
|
keyMaterialCombinations) {
|
||||||
|
final HKDFParameterSpec.Builder b =
|
||||||
|
HKDFParameterSpec.ofExtract();
|
||||||
|
SecretKey baseKey = ctx.baseKey.get();
|
||||||
|
if (baseKey instanceof SecretKeySpec) {
|
||||||
|
addKeyMaterial(keyMaterialCombination, baseKey.getEncoded(),
|
||||||
|
b::addIKM, b::addIKM);
|
||||||
|
} else if (baseKey != null) {
|
||||||
|
b.addIKM(baseKey);
|
||||||
|
}
|
||||||
|
if (ctx.salt != null) {
|
||||||
|
addKeyMaterial(keyMaterialCombination, ctx.salt, b::addSalt,
|
||||||
|
b::addSalt);
|
||||||
|
}
|
||||||
|
if (type == KdfParamSpecType.EXTRACT) {
|
||||||
|
kdfParamSpecs.add(b.extractOnly());
|
||||||
|
} else {
|
||||||
|
kdfParamSpecs.add(b.thenExpand(ctx.info,
|
||||||
|
ctx.expectedOKM.length));
|
||||||
|
}
|
||||||
|
if (ctx.salt == null && !(baseKey instanceof SecretKeySpec)) {
|
||||||
|
// If the salt is null and the IKM is a non-SecretKeySpec
|
||||||
|
// (i.e. is a P11Key.P11SecretKey), the key material
|
||||||
|
// cannot be split and there will be a single
|
||||||
|
// HKDFParameterSpec to test.
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
assert type == KdfParamSpecType.EXPAND : "Unexpected type.";
|
||||||
|
kdfParamSpecs.add(HKDFParameterSpec.expandOnly(
|
||||||
|
new SecretKeySpec(ctx.expectedPRK, "Generic"), ctx.info,
|
||||||
|
ctx.expectedOKM.length));
|
||||||
|
}
|
||||||
|
return kdfParamSpecs;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void checkOpWithDerivedKey(TestContext ctx,
|
||||||
|
SecretKey derivedKey, Provider p) throws Exception {
|
||||||
|
byte[] opOut;
|
||||||
|
switch (ctx.derivedKeyAlg) {
|
||||||
|
case "AES" -> {
|
||||||
|
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding", p);
|
||||||
|
cipher.init(Cipher.ENCRYPT_MODE, derivedKey,
|
||||||
|
new IvParameterSpec(new byte[16]));
|
||||||
|
opOut = cipher.doFinal(knownBytes);
|
||||||
|
}
|
||||||
|
case "Generic" -> {
|
||||||
|
Mac hmac = Mac.getInstance("HmacSHA256", p);
|
||||||
|
hmac.init(derivedKey);
|
||||||
|
opOut = hmac.doFinal(knownBytes);
|
||||||
|
}
|
||||||
|
default -> throw new RuntimeException(
|
||||||
|
"Unexpected derived key algorithm.");
|
||||||
|
}
|
||||||
|
printByteArrayAssertion("Operation output", opOut, ctx.expectedOpOut);
|
||||||
|
if (!Arrays.equals(opOut, ctx.expectedOpOut)) {
|
||||||
|
throw new HkdfTestAssertionException(
|
||||||
|
"Operation with derived key failure.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void checkDerivationData(String derivationType,
|
||||||
|
byte[] derivedKey, byte[] derivedData, byte[] expectedData)
|
||||||
|
throws Exception {
|
||||||
|
printByteArrayAssertion(derivationType + " key derivation", derivedKey,
|
||||||
|
expectedData);
|
||||||
|
printByteArrayAssertion(derivationType + " data derivation",
|
||||||
|
derivedData, expectedData);
|
||||||
|
if (!Arrays.equals(derivedKey, expectedData) ||
|
||||||
|
!Arrays.equals(derivedData, expectedData)) {
|
||||||
|
throw new HkdfTestAssertionException(
|
||||||
|
derivationType + " derivation failure.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void executeDerivationForKdfParamSpec(TestContext ctx,
|
||||||
|
KdfParamSpecType type, KDF kdf, AlgorithmParameterSpec kdfParamSpec,
|
||||||
|
Provider p) throws Exception {
|
||||||
|
printDerivationInfo(ctx, type, kdfParamSpec, p);
|
||||||
|
printHeader("HKDF derivation: output", '-', 10);
|
||||||
|
String derivedKeyAlg = type == KdfParamSpecType.EXTRACT ?
|
||||||
|
"Generic" : ctx.derivedKeyAlg;
|
||||||
|
SecretKey derivedKey = kdf.deriveKey(derivedKeyAlg, kdfParamSpec);
|
||||||
|
byte[] derivedData = kdf.deriveData(kdfParamSpec);
|
||||||
|
if (type == KdfParamSpecType.EXPAND ||
|
||||||
|
type == KdfParamSpecType.EXTRACT_EXPAND) {
|
||||||
|
checkDerivationData("Extract", derivedKey.getEncoded(),
|
||||||
|
derivedData, ctx.expectedOKM);
|
||||||
|
checkOpWithDerivedKey(ctx, derivedKey, p);
|
||||||
|
} else {
|
||||||
|
assert type == KdfParamSpecType.EXTRACT : "Unexpected type.";
|
||||||
|
checkDerivationData("Expand", derivedKey.getEncoded(),
|
||||||
|
derivedData, ctx.expectedPRK);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void crossCheckTestExpectedData(TestContext ctx,
|
||||||
|
KdfParamSpecType type, AlgorithmParameterSpec kdfParamSpec)
|
||||||
|
throws Exception {
|
||||||
|
try {
|
||||||
|
Provider sunJCE = Security.getProvider("SunJCE");
|
||||||
|
KDF kdf = KDF.getInstance(ctx.hkdfAlg, sunJCE);
|
||||||
|
executeDerivationForKdfParamSpec(ctx, type, kdf, kdfParamSpec,
|
||||||
|
sunJCE);
|
||||||
|
} catch (HkdfTestAssertionException e) {
|
||||||
|
// Fail if derivation was possible and the assertion data in this
|
||||||
|
// test is inconsistent with SunJCE. This should never happen.
|
||||||
|
throw e;
|
||||||
|
} catch (Exception e) {
|
||||||
|
// Cross-checking of the expected data in this test is a
|
||||||
|
// best-effort. If derivation was not possible (e.g. SunJCE does
|
||||||
|
// not support the HKDF algorithm), do not fail.
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void reportTestFailure(Exception e) {
|
||||||
|
testFailed = true;
|
||||||
|
printHeader("TEST FAILED", 'x', 10);
|
||||||
|
e.printStackTrace(debugPrinter);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void executeDerivation(TestContext ctx,
|
||||||
|
KdfParamSpecType type) {
|
||||||
|
try {
|
||||||
|
KDF kdf = KDF.getInstance(ctx.hkdfAlg, p11Provider);
|
||||||
|
List<AlgorithmParameterSpec> kdfParamSpecs =
|
||||||
|
generateKdfParamSpecs(ctx, type);
|
||||||
|
crossCheckTestExpectedData(ctx, type, kdfParamSpecs.get(0));
|
||||||
|
for (AlgorithmParameterSpec kdfParamSpec : kdfParamSpecs) {
|
||||||
|
executeDerivationForKdfParamSpec(ctx, type, kdf, kdfParamSpec,
|
||||||
|
p11Provider);
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
reportTestFailure(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static byte[] hexStringToByteArray(String hexString) {
|
||||||
|
return hexString != null ? hex.parseHex(hexString) : null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void executeTest(String testHeader, String hkdfAlg,
|
||||||
|
String derivedKeyAlg, SecretKey baseKey, String saltHex,
|
||||||
|
String infoHex, String expectedPRKHex, String expectedOKMHex,
|
||||||
|
String expectedOpOutHex) {
|
||||||
|
executeTest(testHeader, hkdfAlg, derivedKeyAlg, ()-> baseKey, saltHex,
|
||||||
|
infoHex, expectedPRKHex, expectedOKMHex, expectedOpOutHex);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void executeTest(String testHeader, String hkdfAlg,
|
||||||
|
String derivedKeyAlg, String baseKeyHex, String saltHex,
|
||||||
|
String infoHex, String expectedPRKHex, String expectedOKMHex,
|
||||||
|
String expectedOpOutHex) {
|
||||||
|
executeTest(testHeader, hkdfAlg, derivedKeyAlg,
|
||||||
|
()-> new SecretKeySpec(hexStringToByteArray(baseKeyHex),
|
||||||
|
"Generic"), saltHex, infoHex, expectedPRKHex,
|
||||||
|
expectedOKMHex, expectedOpOutHex);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void executeTest(String testHeader, String hkdfAlg,
|
||||||
|
String derivedKeyAlg, Supplier<SecretKey> baseKey, String saltHex,
|
||||||
|
String infoHex, String expectedPRKHex, String expectedOKMHex,
|
||||||
|
String expectedOpOutHex) {
|
||||||
|
printTestHeader(testHeader);
|
||||||
|
TestContext ctx = new TestContext(hkdfAlg, derivedKeyAlg, baseKey,
|
||||||
|
hexStringToByteArray(saltHex),
|
||||||
|
hexStringToByteArray(infoHex),
|
||||||
|
hexStringToByteArray(expectedPRKHex),
|
||||||
|
hexStringToByteArray(expectedOKMHex),
|
||||||
|
hexStringToByteArray(expectedOpOutHex));
|
||||||
|
executeDerivation(ctx, KdfParamSpecType.EXTRACT_EXPAND);
|
||||||
|
executeDerivation(ctx, KdfParamSpecType.EXTRACT);
|
||||||
|
executeDerivation(ctx, KdfParamSpecType.EXPAND);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void printTestHeader(String testHeader) {
|
||||||
|
debugPrinter.println();
|
||||||
|
debugPrinter.println("=".repeat(testHeader.length()));
|
||||||
|
debugPrinter.println(testHeader);
|
||||||
|
debugPrinter.println("=".repeat(testHeader.length()));
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void printHeader(String header, char sepChar, int sepCount) {
|
||||||
|
String sepBlock = String.valueOf(sepChar).repeat(sepCount);
|
||||||
|
debugPrinter.println(sepBlock + " " + header + " " + sepBlock);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void printDerivationKeyMaterial(String header,
|
||||||
|
List<SecretKey> keyMaterial, KdfParamSpecType type) {
|
||||||
|
if (keyMaterial != null && !keyMaterial.isEmpty()) {
|
||||||
|
debugPrinter.println(header + ":");
|
||||||
|
for (SecretKey km : keyMaterial) {
|
||||||
|
debugPrinter.print(" ".repeat(2));
|
||||||
|
if (km instanceof SecretKeySpec) {
|
||||||
|
debugPrinter.println(hex.formatHex(km.getEncoded()));
|
||||||
|
} else {
|
||||||
|
debugPrinter.println(km);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if (type == KdfParamSpecType.EXTRACT ||
|
||||||
|
type == KdfParamSpecType.EXTRACT_EXPAND) {
|
||||||
|
debugPrinter.println(header + ": NULL");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void printDerivationInfo(TestContext ctx,
|
||||||
|
KdfParamSpecType type, AlgorithmParameterSpec kdfParamSpec,
|
||||||
|
Provider p) {
|
||||||
|
debugPrinter.println();
|
||||||
|
printHeader("HKDF derivation: input", '-', 10);
|
||||||
|
debugPrinter.println("Algorithm: " + ctx.hkdfAlg);
|
||||||
|
debugPrinter.println("Provider: " + p.getName());
|
||||||
|
debugPrinter.println("Derivation type: " + type);
|
||||||
|
List<SecretKey> ikms = null;
|
||||||
|
List<SecretKey> salts = null;
|
||||||
|
byte[] info = null;
|
||||||
|
Integer length = null;
|
||||||
|
switch (kdfParamSpec) {
|
||||||
|
case HKDFParameterSpec.Extract asExtract -> {
|
||||||
|
debugPrinter.println("Derived key type: PRK (Generic)");
|
||||||
|
salts = asExtract.salts();
|
||||||
|
ikms = asExtract.ikms();
|
||||||
|
}
|
||||||
|
case HKDFParameterSpec.ExtractThenExpand asExtractExpand -> {
|
||||||
|
debugPrinter.println("Derived key type: " + ctx.derivedKeyAlg);
|
||||||
|
salts = asExtractExpand.salts();
|
||||||
|
ikms = asExtractExpand.ikms();
|
||||||
|
info = asExtractExpand.info();
|
||||||
|
length = asExtractExpand.length();
|
||||||
|
}
|
||||||
|
case HKDFParameterSpec.Expand asExpand -> {
|
||||||
|
debugPrinter.println("Derived key type: " + ctx.derivedKeyAlg);
|
||||||
|
info = asExpand.info();
|
||||||
|
length = asExpand.length();
|
||||||
|
}
|
||||||
|
case null, default -> throw new RuntimeException(
|
||||||
|
"Unrecognized AlgorithmParameterSpec class.");
|
||||||
|
}
|
||||||
|
printDerivationKeyMaterial("Salts", salts, type);
|
||||||
|
printDerivationKeyMaterial("IKMs", ikms, type);
|
||||||
|
if (info != null) {
|
||||||
|
debugPrinter.println("Info: " + hex.formatHex(info));
|
||||||
|
} else if (type == KdfParamSpecType.EXPAND ||
|
||||||
|
type == KdfParamSpecType.EXTRACT_EXPAND) {
|
||||||
|
debugPrinter.println("Info: NULL");
|
||||||
|
}
|
||||||
|
if (length != null) {
|
||||||
|
debugPrinter.println("Length: " + length);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void printByteArrayAssertion(String desc, byte[] actual,
|
||||||
|
byte[] expected) {
|
||||||
|
debugPrinter.println(desc + " (actual):");
|
||||||
|
debugPrinter.println(actual != null ? hex.formatHex(actual) : "null");
|
||||||
|
debugPrinter.println(desc + " (expected):");
|
||||||
|
debugPrinter.println(expected != null ? hex.formatHex(expected) :
|
||||||
|
"null");
|
||||||
|
}
|
||||||
|
|
||||||
|
private static SecretKey doKeyAgreement(String algorithm, PrivateKey privK,
|
||||||
|
PublicKey pubK) throws Exception {
|
||||||
|
KeyAgreement ka = KeyAgreement.getInstance(algorithm, p11Provider);
|
||||||
|
ka.init(privK);
|
||||||
|
ka.doPhase(pubK, true);
|
||||||
|
return ka.generateSecret("TlsPremasterSecret");
|
||||||
|
}
|
||||||
|
|
||||||
|
private static SecretKey getTlsPremasterSecretWithDHExchange(String xHex,
|
||||||
|
String yHex, String pHex, String gHex) throws Exception {
|
||||||
|
KeyFactory kf = KeyFactory.getInstance("DH", p11Provider);
|
||||||
|
BigInteger p = new BigInteger(pHex, 16);
|
||||||
|
BigInteger g = new BigInteger(gHex, 16);
|
||||||
|
PrivateKey privK = kf.generatePrivate(new DHPrivateKeySpec(
|
||||||
|
new BigInteger(xHex, 16), p, g));
|
||||||
|
PublicKey pubK = kf.generatePublic(new DHPublicKeySpec(
|
||||||
|
new BigInteger(yHex, 16), p, g));
|
||||||
|
return doKeyAgreement("DH", privK, pubK);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static SecretKey getTlsPremasterSecretWithECDHExchange(String s,
|
||||||
|
String wx, String wy) throws Exception {
|
||||||
|
AlgorithmParameters p =
|
||||||
|
AlgorithmParameters.getInstance("EC", p11Provider);
|
||||||
|
p.init(new ECGenParameterSpec("secp256r1"));
|
||||||
|
ECParameterSpec params = p.getParameterSpec(ECParameterSpec.class);
|
||||||
|
KeyFactory kf = KeyFactory.getInstance("EC", p11Provider);
|
||||||
|
PrivateKey privK = kf.generatePrivate(new ECPrivateKeySpec(
|
||||||
|
new BigInteger(s), params));
|
||||||
|
ECPoint publicPoint = new ECPoint(new BigInteger(wx),
|
||||||
|
new BigInteger(wy));
|
||||||
|
PublicKey pubK = kf.generatePublic(new ECPublicKeySpec(
|
||||||
|
publicPoint, params));
|
||||||
|
return doKeyAgreement("ECDH", privK, pubK);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void test_RFC_5869_case_1() {
|
||||||
|
executeTest("RFC 5869 - Test Case 1",
|
||||||
|
"HKDF-SHA256",
|
||||||
|
"Generic",
|
||||||
|
"0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b",
|
||||||
|
"000102030405060708090a0b0c",
|
||||||
|
"f0f1f2f3f4f5f6f7f8f9",
|
||||||
|
"077709362c2e32df0ddc3f0dc47bba6390b6c73bb50f9c3122ec844ad7c2" +
|
||||||
|
"b3e5",
|
||||||
|
"3cb25f25faacd57a90434f64d0362f2a2d2d0a90cf1a5a4c5db02d56ecc4" +
|
||||||
|
"c5bf34007208d5b887185865",
|
||||||
|
"ad9e90d0c59d47539899647a3baf0fd364c54eeb5f4d0b80e1f39579e434" +
|
||||||
|
"e801");
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void test_RFC_5869_case_2() {
|
||||||
|
executeTest("RFC 5869 - Test Case 2",
|
||||||
|
"HKDF-SHA256",
|
||||||
|
"Generic",
|
||||||
|
"000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d" +
|
||||||
|
"1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b" +
|
||||||
|
"3c3d3e3f404142434445464748494a4b4c4d4e4f",
|
||||||
|
"606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d" +
|
||||||
|
"7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b" +
|
||||||
|
"9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeaf",
|
||||||
|
"b0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccd" +
|
||||||
|
"cecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaeb" +
|
||||||
|
"ecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff",
|
||||||
|
"06a6b88c5853361a06104c9ceb35b45cef760014904671014a193f40c15f" +
|
||||||
|
"c244",
|
||||||
|
"b11e398dc80327a1c8e7f78c596a49344f012eda2d4efad8a050cc4c19af" +
|
||||||
|
"a97c59045a99cac7827271cb41c65e590e09da3275600c2f09b8367793a9" +
|
||||||
|
"aca3db71cc30c58179ec3e87c14c01d5c1f3434f1d87",
|
||||||
|
"eabe8bc548bf430aedc423e9d7df94125eacff3dbb3b95b50379246c2546" +
|
||||||
|
"01da");
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void test_RFC_5869_case_3() {
|
||||||
|
executeTest("RFC 5869 - Test Case 3",
|
||||||
|
"HKDF-SHA256",
|
||||||
|
"Generic",
|
||||||
|
"0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b",
|
||||||
|
null,
|
||||||
|
null,
|
||||||
|
"19ef24a32c717b167f33a91d6f648bdf96596776afdb6377ac434c1c293c" +
|
||||||
|
"cb04",
|
||||||
|
"8da4e775a563c18f715f802a063c5a31b8a11f5c5ee1879ec3454e5f3c73" +
|
||||||
|
"8d2d9d201395faa4b61a96c8",
|
||||||
|
"06828b5679679681be59aa2822869cb1a174319e53a545e3301bd832ae3e" +
|
||||||
|
"513f");
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void test_AES_HKDFWithHmacSHA256() {
|
||||||
|
executeTest("AES - HKDF-SHA256",
|
||||||
|
"HKDF-SHA256",
|
||||||
|
"AES",
|
||||||
|
"000102030405060708090a0b0c0d0e0f",
|
||||||
|
"101112131415161718191a1b1c1d1e1f",
|
||||||
|
"a0a1a2a3a4a5a6a7a8a9aaabacadaeaf",
|
||||||
|
"0ecd9f09ddfc6b7bcad2646fa6bc10f922e5489a4ea755ec87ec1b7df379" +
|
||||||
|
"85ca",
|
||||||
|
"b97b1b4ce098f8e22f2f38b60d9f7a0e5902a1193602a876c010d73009dd" +
|
||||||
|
"0701",
|
||||||
|
"646e0175bcef43b9ebd2a3884699ad40b34d4b011e91679c5f25f0721d36" +
|
||||||
|
"7f6a");
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void test_AES_HKDFWithHmacSHA384() {
|
||||||
|
executeTest("AES - HKDF-SHA384",
|
||||||
|
"HKDF-SHA384",
|
||||||
|
"AES",
|
||||||
|
"000102030405060708090a0b0c0d0e0f",
|
||||||
|
"101112131415161718191a1b1c1d1e1f",
|
||||||
|
"a0a1a2a3a4a5a6a7a8a9aaabacadaeaf",
|
||||||
|
"31ca88a527220f8271d78df4ce6c4d973f135ad37973b96644b4d52d499d" +
|
||||||
|
"0a2b03d53c875b1176b089e1e6161ab6d92b",
|
||||||
|
"ba91a67e4d7640495194916ef1252418a651103fbddb0f2ec8b9d1f44f7a" +
|
||||||
|
"7a0d",
|
||||||
|
"f3cfcb44d7b36dce96f584c74118b434e714a13448321063241fd24ace11" +
|
||||||
|
"f2a0");
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void test_AES_HKDFWithHmacSHA512() {
|
||||||
|
executeTest("AES - HKDF-SHA512",
|
||||||
|
"HKDF-SHA512",
|
||||||
|
"AES",
|
||||||
|
"000102030405060708090a0b0c0d0e0f",
|
||||||
|
"101112131415161718191a1b1c1d1e1f",
|
||||||
|
"a0a1a2a3a4a5a6a7a8a9aaabacadaeaf",
|
||||||
|
"f6e6b1ddb24ea0f0ede0f533d1f350c86bf78966b0e5fd2af34dd00dae39" +
|
||||||
|
"01d6279fe8111d6572e3cd05f2f0eeabb9144dc0da9437cdf37b0c6d7f3b" +
|
||||||
|
"1064ab2b",
|
||||||
|
"302212eb57ae758874e0e52fbdfa4eee29d7c694f181b21d8a8b571a43ce" +
|
||||||
|
"aad5",
|
||||||
|
"94459a6593f9c2cfea2ad32970efb8506f3a927927ba283fb6bfd7111aa8" +
|
||||||
|
"63fc");
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void test_AES_HKDFWithHmacSHA256_EmptyBaseKey() {
|
||||||
|
executeTest("AES - HKDF-SHA256 (empty base key)",
|
||||||
|
"HKDF-SHA256",
|
||||||
|
"AES",
|
||||||
|
(SecretKey) null,
|
||||||
|
"101112131415161718191a1b1c1d1e1f",
|
||||||
|
"a0a1a2a3a4a5a6a7a8a9aaabacadaeaf",
|
||||||
|
"cc267bd9515c1eba2cf6aaa1fc8380677f4351fcbea6d70873df5a334efc" +
|
||||||
|
"ee0d",
|
||||||
|
"cf353a33460b146c0eae3f0788ee281e5a0be15280fbeba107472aa1cd58" +
|
||||||
|
"d111",
|
||||||
|
"326e9028f51c05c1919215bad6e35668c94c88040c3777e8e6f8b6acdece" +
|
||||||
|
"85fa");
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void test_AES_HKDFWithHmacSHA256_EmptyBaseKeySaltInfo() {
|
||||||
|
executeTest("AES - HKDF-SHA256 (empty base key, salt, and info)",
|
||||||
|
"HKDF-SHA256",
|
||||||
|
"AES",
|
||||||
|
(SecretKey) null,
|
||||||
|
null,
|
||||||
|
null,
|
||||||
|
"b613679a0814d9ec772f95d778c35fc5ff1697c493715653c6c712144292" +
|
||||||
|
"c5ad",
|
||||||
|
"eb70f01dede9afafa449eee1b1286504e1f62388b3f7dd4f956697b0e828" +
|
||||||
|
"fe18",
|
||||||
|
"3fdcf83994f6e0a6f6f482d097e242355e255a8ed17e661a71ca2d592c7a" +
|
||||||
|
"884e");
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void test_HKDF_after_DH_HkdfSHA256() throws Exception {
|
||||||
|
SecretKey tlsPremasterSecret = getTlsPremasterSecretWithDHExchange(
|
||||||
|
"00bcb8fa0a6b569961782a394599a1a02a05532a836819908a9a9000ed",
|
||||||
|
"58ceab52f470026eaea24eb250e08d7cc23f21dda57ad628d14eab788633" +
|
||||||
|
"cebc78c565f9292e6cfe9910d51c4878f590c46cbf380e19acf55cd468ab" +
|
||||||
|
"672afb29c09b7edfd522d034019eadae75ea99bacf1e166548f092a5d371" +
|
||||||
|
"930a275cbcb4bb02cb1d1b7a8bf3751dc85e61fb674059deef54e8ebbd36" +
|
||||||
|
"3bdac4f85c5e49cb7dc8720a8088f047f319a63c2722a720e187f827578b" +
|
||||||
|
"2545041bb5e640454e791f683622bb5aba4ab9bc51001c59bba5cd6cc0e2" +
|
||||||
|
"aec00b0a5313a27454a93d3bd3f2ae5ab1c13165d1564e3b2d60629302b3" +
|
||||||
|
"6bf44c1991bad279d3bd51b142294007f0c8828c9060d8b9b4cc6d335bcc" +
|
||||||
|
"ce31d4e6aa18fd3ce99cb92aec09de2d",
|
||||||
|
"00ffffffffffffffffc90fdaa22168c234c4c6628b80dc1cd129024e088a" +
|
||||||
|
"67cc74020bbea63b139b22514a08798e3404ddef9519b3cd3a431b302b0a" +
|
||||||
|
"6df25f14374fe1356d6d51c245e485b576625e7ec6f44c42e9a637ed6b0b" +
|
||||||
|
"ff5cb6f406b7edee386bfb5a899fa5ae9f24117c4b1fe649286651ece45b" +
|
||||||
|
"3dc2007cb8a163bf0598da48361c55d39a69163fa8fd24cf5f83655d23dc" +
|
||||||
|
"a3ad961c62f356208552bb9ed529077096966d670c354e4abc9804f1746c" +
|
||||||
|
"08ca18217c32905e462e36ce3be39e772c180e86039b2783a2ec07a28fb5" +
|
||||||
|
"c55df06f4c52c9de2bcbf6955817183995497cea956ae515d2261898fa05" +
|
||||||
|
"1015728e5a8aacaa68ffffffffffffffff",
|
||||||
|
"02"
|
||||||
|
);
|
||||||
|
executeTest("Test HKDF-SHA256 after DH exchange (TLS)",
|
||||||
|
"HKDF-SHA256",
|
||||||
|
"Generic",
|
||||||
|
tlsPremasterSecret,
|
||||||
|
null,
|
||||||
|
null,
|
||||||
|
"e3cf8e5e0892ad251a5863c7f6ddc4fb988b1a723a30d3fe1ac235799caf" +
|
||||||
|
"86e1",
|
||||||
|
"86e508974080cdad9fa4407e253d35ae48f40e0e266c91dd04c775538c17" +
|
||||||
|
"0eacd71bb4d54ba0c5065091",
|
||||||
|
"2e94c8c852d318887fa94dac544c369bc25879efd39683a9dc5eda55f565" +
|
||||||
|
"88c0");
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void test_HKDF_after_ECDH_HkdfSHA256() throws Exception {
|
||||||
|
SecretKey tlsPremasterSecret = getTlsPremasterSecretWithECDHExchange(
|
||||||
|
"312092587041182431404764856027482553256569653405119712868911" +
|
||||||
|
"21589605635583946",
|
||||||
|
"851398477998049170325388348439523125186814652510003800309225" +
|
||||||
|
"34333070929362623",
|
||||||
|
"531080873930420952237875954830357399317339863932672261700603" +
|
||||||
|
"26242234504331049");
|
||||||
|
executeTest("Test HKDF-SHA256 after ECDH exchange (TLS)",
|
||||||
|
"HKDF-SHA256",
|
||||||
|
"Generic",
|
||||||
|
tlsPremasterSecret,
|
||||||
|
null,
|
||||||
|
null,
|
||||||
|
"638d8874237f12e42b366090ee8a0207d28a1ac8fd12b6a753ecb58c31cd" +
|
||||||
|
"6a5e",
|
||||||
|
"348a1afabe9560d3a0a6577e8bd66f0e8dc43b4ad52037f692ea5d28fbb2" +
|
||||||
|
"bc963ef59eba65a83befc465",
|
||||||
|
"bab55b2106b4fee07b7afc905ed7c1e84889e941fbc12f132c706addcfc0" +
|
||||||
|
"6e09");
|
||||||
|
}
|
||||||
|
|
||||||
|
public void main(Provider p) throws Exception {
|
||||||
|
p11Provider = p;
|
||||||
|
p11GenericSkf = SecretKeyFactory.getInstance("Generic", p11Provider);
|
||||||
|
for (Method m : TestHKDF.class.getDeclaredMethods()) {
|
||||||
|
if (m.getName().startsWith("test")) {
|
||||||
|
m.invoke(null);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (DEBUG || testFailed) {
|
||||||
|
debugPrinter.flush();
|
||||||
|
System.out.println(debugOut);
|
||||||
|
}
|
||||||
|
if (testFailed) {
|
||||||
|
throw new Exception("TEST FAILED");
|
||||||
|
}
|
||||||
|
System.out.println("TEST PASS - OK");
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void main(String[] args) throws Exception {
|
||||||
|
main(new TestHKDF(), args);
|
||||||
|
}
|
||||||
|
}
|
Loading…
Add table
Add a link
Reference in a new issue