Skip to content

Commit c141aa1

Browse files
committed
8347596: Update HSS/LMS public key encoding
Reviewed-by: mullan Backport-of: 0ee6ba9
1 parent 467f407 commit c141aa1

File tree

3 files changed

+32
-23
lines changed

3 files changed

+32
-23
lines changed

src/java.base/share/classes/sun/security/provider/HSS.java

+12-10
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved.
2+
* Copyright (c) 2023, 2025, Oracle and/or its affiliates. All rights reserved.
33
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
44
*
55
* This code is free software; you can redistribute it and/or modify it
@@ -757,12 +757,8 @@ static class HSSPublicKey extends X509Key implements Serializable {
757757
Arrays.copyOfRange(keyArray, 4, keyArray.length),
758758
0, true);
759759
algid = new AlgorithmId(ObjectIdentifier.of(KnownOIDs.HSSLMS));
760-
byte[] derEncodedKeyarray =
761-
new DerOutputStream()
762-
.putOctetString(keyArray)
763-
.toByteArray();
764760
this.setKey(new BitArray(
765-
8 * derEncodedKeyarray.length, derEncodedKeyarray));
761+
8 * keyArray.length, keyArray));
766762
}
767763
}
768764

@@ -783,11 +779,17 @@ public String toString() {
783779
@Override
784780
protected void parseKeyBits() throws InvalidKeyException {
785781
byte[] keyArray = getKey().toByteArray();
786-
if ((keyArray[0] != DerValue.tag_OctetString) || (keyArray[1] != keyArray.length -2)) {
787-
throw new InvalidKeyException("Bad X509Key");
782+
if (keyArray.length < 12) { // More length check in LMSPublicKey
783+
throw new InvalidKeyException("LMS public key is too short");
784+
}
785+
if (keyArray[0] == DerValue.tag_OctetString
786+
&& keyArray[1] == keyArray.length - 2) {
787+
// pre-8347596 format that has an inner OCTET STRING.
788+
keyArray = Arrays.copyOfRange(keyArray, 2, keyArray.length);
789+
setKey(new BitArray(keyArray.length * 8, keyArray));
788790
}
789-
L = LMSUtils.fourBytesToInt(keyArray, 2);
790-
lmsPublicKey = new LMSPublicKey(keyArray, 6, true);
791+
L = LMSUtils.fourBytesToInt(keyArray, 0);
792+
lmsPublicKey = new LMSPublicKey(keyArray, 4, true);
791793
}
792794

793795
@java.io.Serial

src/java.base/share/classes/sun/security/util/KeyUtil.java

+1-1
Original file line numberDiff line numberDiff line change
@@ -403,7 +403,7 @@ public static String hashAlgFromHSS(PublicKey publicKey)
403403
try {
404404
DerValue val = new DerValue(publicKey.getEncoded());
405405
val.data.getDerValue();
406-
byte[] rawKey = new DerValue(val.data.getBitString()).getOctetString();
406+
byte[] rawKey = val.data.getBitString();
407407
// According to https://www.rfc-editor.org/rfc/rfc8554.html:
408408
// Section 6.1: HSS public key is u32str(L) || pub[0], where pub[0]
409409
// is the LMS public key for the top-level tree.

test/jdk/sun/security/provider/hss/TestHSS.java

+19-12
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved.
2+
* Copyright (c) 2023, 2025, Oracle and/or its affiliates. All rights reserved.
33
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
44
*
55
* This code is free software; you can redistribute it and/or modify it
@@ -23,7 +23,7 @@
2323

2424
/*
2525
* @test
26-
* @bug 8298127
26+
* @bug 8298127 8347596
2727
* @library /test/lib
2828
* @summary tests for HSS/LMS provider
2929
* @modules java.base/sun.security.util
@@ -40,6 +40,7 @@
4040
import java.security.spec.X509EncodedKeySpec;
4141
import java.util.HexFormat;
4242

43+
import jdk.test.lib.Asserts;
4344
import sun.security.util.*;
4445

4546
import jdk.test.lib.util.SerializationUtils;
@@ -61,9 +62,7 @@ public static void main(String[] args) throws Exception {
6162
i++;
6263
}
6364

64-
if (!serializeTest()) {
65-
throw new RuntimeException("serializeTest failed");
66-
}
65+
serializeTest();
6766

6867
System.out.println("All tests passed");
6968
}
@@ -88,7 +87,7 @@ static boolean kat(TestCase t) throws Exception {
8887
}
8988
}
9089

91-
static boolean serializeTest() throws Exception {
90+
static void serializeTest() throws Exception {
9291
final ObjectIdentifier oid;
9392
var pk = decode("""
9493
00000002
@@ -106,7 +105,19 @@ static boolean serializeTest() throws Exception {
106105
throw new AssertionError(e);
107106
}
108107

109-
var keyBits = new DerOutputStream().putOctetString(pk).toByteArray();
108+
// Encoding without inner OCTET STRING
109+
var pk0 = makeKey(oid, pk);
110+
// Encoding with inner OCTET STRING
111+
var pk1 = makeKey(oid, new DerOutputStream().putOctetString(pk).toByteArray());
112+
Asserts.assertEquals(pk0, pk1);
113+
114+
PublicKey pk2 = (PublicKey) SerializationUtils
115+
.deserialize(SerializationUtils.serialize(pk1));
116+
Asserts.assertEquals(pk1, pk2);
117+
}
118+
119+
static PublicKey makeKey(ObjectIdentifier oid, byte[] keyBits)
120+
throws Exception {
110121
var oidBytes = new DerOutputStream().write(DerValue.tag_Sequence,
111122
new DerOutputStream().putOID(oid));
112123
var x509encoding = new DerOutputStream().write(DerValue.tag_Sequence,
@@ -115,11 +126,7 @@ static boolean serializeTest() throws Exception {
115126
.toByteArray();
116127

117128
var x509KeySpec = new X509EncodedKeySpec(x509encoding);
118-
var pk1 = KeyFactory.getInstance(ALG).generatePublic(x509KeySpec);
119-
120-
PublicKey pk2 = (PublicKey) SerializationUtils
121-
.deserialize(SerializationUtils.serialize(pk1));
122-
return pk2.equals(pk1);
129+
return KeyFactory.getInstance(ALG).generatePublic(x509KeySpec);
123130
}
124131

125132
static boolean verify(byte[] pk, byte[] sig, byte[] msg) throws Exception {

0 commit comments

Comments
 (0)