Skip to content

Commit bc52ac6

Browse files
committed
Polish 'Reactor PemPrivateKeyParser to use DerElement'
See gh-39162
1 parent cc6303f commit bc52ac6

File tree

1 file changed

+102
-101
lines changed

1 file changed

+102
-101
lines changed

spring-boot-project/spring-boot/src/main/java/org/springframework/boot/ssl/pem/PemPrivateKeyParser.java

Lines changed: 102 additions & 101 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2012-2023 the original author or authors.
2+
* Copyright 2012-2024 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -30,7 +30,10 @@
3030
import java.util.Arrays;
3131
import java.util.Base64;
3232
import java.util.Collections;
33+
import java.util.HashMap;
34+
import java.util.HexFormat;
3335
import java.util.List;
36+
import java.util.Map;
3437
import java.util.function.BiFunction;
3538
import java.util.regex.Matcher;
3639
import java.util.regex.Pattern;
@@ -74,6 +77,26 @@ final class PemPrivateKeyParser {
7477

7578
public static final int BASE64_TEXT_GROUP = 1;
7679

80+
private static final EncodedOid RSA_ALGORITHM = EncodedOid.OID_1_2_840_113549_1_1_1;
81+
82+
private static final EncodedOid ELLIPTIC_CURVE_ALGORITHM = EncodedOid.OID_1_2_840_10045_2_1;
83+
84+
private static final EncodedOid ELLIPTIC_CURVE_384_BIT = EncodedOid.OID_1_3_132_0_34;
85+
86+
private static final Map<EncodedOid, String> ALGORITHMS;
87+
static {
88+
Map<EncodedOid, String> algorithms = new HashMap<>();
89+
algorithms.put(EncodedOid.OID_1_2_840_113549_1_1_1, "RSA");
90+
algorithms.put(EncodedOid.OID_1_2_840_113549_1_1_10, "RSA");
91+
algorithms.put(EncodedOid.OID_1_2_840_10040_4_1, "DSA");
92+
algorithms.put(EncodedOid.OID_1_3_101_110, "XDH");
93+
algorithms.put(EncodedOid.OID_1_3_101_111, "XDH");
94+
algorithms.put(EncodedOid.OID_1_3_101_112, "EdDSA");
95+
algorithms.put(EncodedOid.OID_1_3_101_113, "EdDSA");
96+
algorithms.put(EncodedOid.OID_1_2_840_10045_2_1, "EC");
97+
ALGORITHMS = Collections.unmodifiableMap(algorithms);
98+
}
99+
77100
private static final List<PemParser> PEM_PARSERS;
78101
static {
79102
List<PemParser> parsers = new ArrayList<>();
@@ -87,51 +110,6 @@ final class PemPrivateKeyParser {
87110
PEM_PARSERS = Collections.unmodifiableList(parsers);
88111
}
89112

90-
/**
91-
* ASN.1 encoded object identifier {@literal 1.2.840.113549.1.1.1}.
92-
*/
93-
private static final int[] RSA_ALGORITHM = { 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x01, 0x01 };
94-
95-
/**
96-
* ASN.1 encoded object identifier {@literal 1.2.840.113549.1.1.10}.
97-
*/
98-
private static final int[] RSASSA_PSS_ALGORITHM = { 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0a };
99-
100-
/**
101-
* ASN.1 encoded object identifier {@literal 1.2.840.10040.4.1}.
102-
*/
103-
private static final int[] DSA_ALGORITHM = { 0x2a, 0x86, 0x48, 0xce, 0x38, 0x04, 0x01 };
104-
105-
/**
106-
* ASN.1 encoded object identifier {@literal 1.3.101.110}.
107-
*/
108-
private static final int[] X25519_ALGORITHM = { 0x2b, 0x65, 0x6e };
109-
110-
/**
111-
* ASN.1 encoded object identifier {@literal 1.3.101.111}.
112-
*/
113-
private static final int[] X448_ALGORITHM = { 0x2b, 0x65, 0x6f };
114-
115-
/**
116-
* ASN.1 encoded object identifier {@literal 1.3.101.112}.
117-
*/
118-
private static final int[] ED448_ALGORITHM = { 0x2b, 0x65, 0x70 };
119-
120-
/**
121-
* ASN.1 encoded object identifier {@literal 1.3.101.113}.
122-
*/
123-
private static final int[] ED25519_ALGORITHM = { 0x2b, 0x65, 0x71 };
124-
125-
/**
126-
* ASN.1 encoded object identifier {@literal 1.2.840.10045.2.1}.
127-
*/
128-
private static final int[] EC_ALGORITHM = { 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x02, 0x01 };
129-
130-
/**
131-
* ASN.1 encoded object identifier {@literal 1.3.132.0.34}.
132-
*/
133-
private static final int[] EC_PARAMETERS = { 0x2b, 0x81, 0x04, 0x00, 0x22 };
134-
135113
private PemPrivateKeyParser() {
136114
}
137115

@@ -152,29 +130,22 @@ private static PKCS8EncodedKeySpec createKeySpecForSec1Ec(byte[] bytes, String p
152130
Assert.state(privateKey != null && privateKey.isType(ValueType.PRIMITIVE, TagType.OCTET_STRING),
153131
"Key spec should contain private key");
154132
DerElement parameters = DerElement.of(ecPrivateKey.getContents());
155-
return createKeySpecForAlgorithm(bytes, EC_ALGORITHM, getEcParameters(parameters));
133+
return createKeySpecForAlgorithm(bytes, ELLIPTIC_CURVE_ALGORITHM, getEcParameters(parameters));
156134
}
157135

158-
private static int[] getEcParameters(DerElement parameters) {
136+
private static EncodedOid getEcParameters(DerElement parameters) {
159137
if (parameters == null) {
160-
return EC_PARAMETERS;
138+
return ELLIPTIC_CURVE_384_BIT;
161139
}
162140
Assert.state(parameters.isType(ValueType.ENCODED), "Key spec should contain encoded parameters");
163141
DerElement contents = DerElement.of(parameters.getContents());
164142
Assert.state(contents.isType(ValueType.PRIMITIVE, TagType.OBJECT_IDENTIFIER),
165143
"Key spec parameters should contain object identifier");
166-
return getOid(contents.getContents());
144+
return EncodedOid.of(contents);
167145
}
168146

169-
private static int[] getOid(ByteBuffer bytes) {
170-
int[] result = new int[bytes.remaining()];
171-
for (int i = 0; i < result.length; i++) {
172-
result[i] = bytes.get() & 0xFF;
173-
}
174-
return result;
175-
}
176-
177-
private static PKCS8EncodedKeySpec createKeySpecForAlgorithm(byte[] bytes, int[] algorithm, int[] parameters) {
147+
private static PKCS8EncodedKeySpec createKeySpecForAlgorithm(byte[] bytes, EncodedOid algorithm,
148+
EncodedOid parameters) {
178149
try {
179150
DerEncoder encoder = new DerEncoder();
180151
encoder.integer(0x00); // Version 0
@@ -200,46 +171,11 @@ private static PKCS8EncodedKeySpec createKeySpecForPkcs8(byte[] bytes, String pa
200171
DerElement sequence = DerElement.of(ecPrivateKey.getContents());
201172
Assert.state(sequence != null && sequence.isType(ValueType.ENCODED, TagType.SEQUENCE),
202173
"Key spec should contain private key");
203-
DerElement algorithmIdentifier = DerElement.of(sequence.getContents());
204-
Assert.state(
205-
algorithmIdentifier != null
206-
&& algorithmIdentifier.isType(ValueType.PRIMITIVE, TagType.OBJECT_IDENTIFIER),
174+
DerElement algorithmId = DerElement.of(sequence.getContents());
175+
Assert.state(algorithmId != null && algorithmId.isType(ValueType.PRIMITIVE, TagType.OBJECT_IDENTIFIER),
207176
"Key spec container object identifier");
208-
int[] oid = getOid(algorithmIdentifier.getContents());
209-
String algorithmName = getAlgorithm(oid);
210-
if (algorithmName != null) {
211-
return new PKCS8EncodedKeySpec(bytes, algorithmName);
212-
}
213-
else {
214-
return new PKCS8EncodedKeySpec(bytes);
215-
}
216-
}
217-
218-
private static String getAlgorithm(int[] oid) {
219-
if (oid == null) {
220-
return null;
221-
}
222-
if (Arrays.equals(RSA_ALGORITHM, oid)) {
223-
return "RSA";
224-
}
225-
else if (Arrays.equals(RSASSA_PSS_ALGORITHM, oid)) {
226-
return "RSASSA-PSS";
227-
}
228-
else if (Arrays.equals(DSA_ALGORITHM, oid)) {
229-
return "DSA";
230-
}
231-
else if (Arrays.equals(ED448_ALGORITHM, oid) || Arrays.equals(ED25519_ALGORITHM, oid)) {
232-
return "EdDSA";
233-
}
234-
else if (Arrays.equals(X448_ALGORITHM, oid) || Arrays.equals(X25519_ALGORITHM, oid)) {
235-
return "XDH";
236-
}
237-
else if (Arrays.equals(EC_ALGORITHM, oid)) {
238-
return "EC";
239-
}
240-
else {
241-
return null;
242-
}
177+
String algorithmName = ALGORITHMS.get(EncodedOid.of(algorithmId));
178+
return (algorithmName != null) ? new PKCS8EncodedKeySpec(bytes, algorithmName) : new PKCS8EncodedKeySpec(bytes);
243179
}
244180

245181
private static PKCS8EncodedKeySpec createKeySpecForPkcs8Encrypted(byte[] bytes, String password) {
@@ -339,9 +275,9 @@ static class DerEncoder {
339275

340276
private final ByteArrayOutputStream stream = new ByteArrayOutputStream();
341277

342-
void objectIdentifier(int... encodedObjectIdentifier) throws IOException {
343-
int code = (encodedObjectIdentifier != null) ? 0x06 : 0x05;
344-
codeLengthBytes(code, bytes(encodedObjectIdentifier));
278+
void objectIdentifier(EncodedOid encodedOid) throws IOException {
279+
int code = (encodedOid != null) ? 0x06 : 0x05;
280+
codeLengthBytes(code, (encodedOid != null) ? encodedOid.toByteArray() : null);
345281
}
346282

347283
void integer(int... encodedInteger) throws IOException {
@@ -537,4 +473,69 @@ private static String getEncryptionAlgorithm(AlgorithmParameters algParameters,
537473

538474
}
539475

476+
/**
477+
* ANS.1 encoded object identifier.
478+
*/
479+
static final class EncodedOid {
480+
481+
static final EncodedOid OID_1_2_840_10040_4_1 = EncodedOid.of("2a8648ce380401");
482+
static final EncodedOid OID_1_2_840_113549_1_1_1 = EncodedOid.of("2A864886F70D010101");
483+
static final EncodedOid OID_1_2_840_113549_1_1_10 = EncodedOid.of("2a864886f70d01010a");
484+
static final EncodedOid OID_1_3_101_110 = EncodedOid.of("2b656e");
485+
static final EncodedOid OID_1_3_101_111 = EncodedOid.of("2b656f");
486+
static final EncodedOid OID_1_3_101_112 = EncodedOid.of("2b6570");
487+
static final EncodedOid OID_1_3_101_113 = EncodedOid.of("2b6571");
488+
static final EncodedOid OID_1_2_840_10045_2_1 = EncodedOid.of("2a8648ce3d0201");
489+
static final EncodedOid OID_1_3_132_0_34 = EncodedOid.of("2b81040022");
490+
491+
private final byte[] value;
492+
493+
private EncodedOid(byte[] value) {
494+
this.value = value;
495+
}
496+
497+
byte[] toByteArray() {
498+
return this.value.clone();
499+
}
500+
501+
@Override
502+
public boolean equals(Object obj) {
503+
if (this == obj) {
504+
return true;
505+
}
506+
if (obj == null || getClass() != obj.getClass()) {
507+
return false;
508+
}
509+
return Arrays.equals(this.value, ((EncodedOid) obj).value);
510+
}
511+
512+
@Override
513+
public int hashCode() {
514+
return Arrays.hashCode(this.value);
515+
}
516+
517+
static EncodedOid of(String hexString) {
518+
return of(HexFormat.of().parseHex(hexString));
519+
}
520+
521+
static EncodedOid of(DerElement derElement) {
522+
return of(derElement.getContents());
523+
}
524+
525+
static EncodedOid of(ByteBuffer byteBuffer) {
526+
return of(byteBuffer.array(), byteBuffer.arrayOffset() + byteBuffer.position(), byteBuffer.remaining());
527+
}
528+
529+
static EncodedOid of(byte[] bytes) {
530+
return of(bytes, 0, bytes.length);
531+
}
532+
533+
static EncodedOid of(byte[] bytes, int off, int len) {
534+
byte[] value = new byte[len];
535+
System.arraycopy(bytes, off, value, 0, len);
536+
return new EncodedOid(value);
537+
}
538+
539+
}
540+
540541
}

0 commit comments

Comments
 (0)