Skip to content

Commit d5ac2ad

Browse files
Alexey Bakhtingnu-andrew
authored andcommitted
8360937: Enhance certificate handling
Reviewed-by: fferrari, andrew Backport-of: d3b1c2be9e87aad07cac29d94679130fe5807c17
1 parent dde48ae commit d5ac2ad

File tree

3 files changed

+92
-8
lines changed

3 files changed

+92
-8
lines changed

jdk/src/share/classes/sun/security/util/DerValue.java

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -822,6 +822,22 @@ public boolean equals(Object o) {
822822
doEquals(other, this);
823823
}
824824

825+
/**
826+
* Checks that the BMPString does not contain any surrogate characters,
827+
* which are outside the Basic Multilingual Plane.
828+
*
829+
* @throws IOException if illegal characters are detected
830+
*/
831+
public void validateBMPString() throws IOException {
832+
String bmpString = getBMPString();
833+
for (int i = 0; i < bmpString.length(); i++) {
834+
if (Character.isSurrogate(bmpString.charAt(i))) {
835+
throw new IOException(
836+
"Illegal character in BMPString, index: " + i);
837+
}
838+
}
839+
}
840+
825841
/**
826842
* Helper for public method equals()
827843
*/

jdk/src/share/classes/sun/security/x509/AVA.java

Lines changed: 52 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 1996, 2011, Oracle and/or its affiliates. All rights reserved.
2+
* Copyright (c) 1996, 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
@@ -30,9 +30,14 @@
3030
import java.io.OutputStream;
3131
import java.io.Reader;
3232
import java.security.AccessController;
33+
import java.nio.charset.Charset;
3334
import java.text.Normalizer;
3435
import java.util.*;
3536

37+
import static java.nio.charset.StandardCharsets.ISO_8859_1;
38+
import static java.nio.charset.StandardCharsets.UTF_8;
39+
import static java.nio.charset.StandardCharsets.UTF_16BE;
40+
3641
import sun.security.action.GetBooleanAction;
3742
import sun.security.util.*;
3843
import sun.security.pkcs.PKCS9Attribute;
@@ -606,6 +611,10 @@ private static boolean trailingSpace(Reader in) throws IOException {
606611
throw new IOException("AVA, extra bytes = "
607612
+ derval.data.available());
608613
}
614+
615+
if (value.tag == DerValue.tag_BMPString) {
616+
value.validateBMPString();
617+
}
609618
}
610619

611620
AVA(DerInputStream in) throws IOException {
@@ -753,7 +762,7 @@ public String toRFC2253String(Map<String, String> oidMap) {
753762
*/
754763
String valStr = null;
755764
try {
756-
valStr = new String(value.getDataBytes(), "UTF8");
765+
valStr = new String(value.getDataBytes(), getCharset(value, false));
757766
} catch (IOException ie) {
758767
throw new IllegalArgumentException("DER Value conversion");
759768
}
@@ -906,7 +915,7 @@ public String toRFC2253CanonicalString() {
906915
*/
907916
String valStr = null;
908917
try {
909-
valStr = new String(value.getDataBytes(), "UTF8");
918+
valStr = new String(value.getDataBytes(), getCharset(value, true));
910919
} catch (IOException ie) {
911920
throw new IllegalArgumentException("DER Value conversion");
912921
}
@@ -1026,6 +1035,46 @@ private static boolean isDerString(DerValue value, boolean canonical) {
10261035
}
10271036
}
10281037

1038+
/*
1039+
* Returns the charset that should be used to decode each DN string type.
1040+
*
1041+
* This method ensures that multi-byte (UTF8String and BMPString) types
1042+
* are decoded using the correct charset and the String forms represent
1043+
* the correct characters. For 8-bit ASCII-based types (PrintableString
1044+
* and IA5String), we return ISO_8859_1 rather than ASCII, so that the
1045+
* complete range of characters can be represented, as many certificates
1046+
* do not comply with the Internationalized Domain Name ACE format.
1047+
*
1048+
* NOTE: this method only supports DirectoryStrings of the types returned
1049+
* by isDerString().
1050+
*/
1051+
private static Charset getCharset(DerValue value, boolean canonical) {
1052+
if (canonical) {
1053+
switch (value.tag) {
1054+
case DerValue.tag_PrintableString:
1055+
return ISO_8859_1;
1056+
case DerValue.tag_UTF8String:
1057+
return UTF_8;
1058+
default:
1059+
throw new Error("unexpected tag: " + value.tag);
1060+
}
1061+
}
1062+
1063+
switch (value.tag) {
1064+
case DerValue.tag_PrintableString:
1065+
case DerValue.tag_T61String:
1066+
case DerValue.tag_IA5String:
1067+
case DerValue.tag_GeneralString:
1068+
return ISO_8859_1;
1069+
case DerValue.tag_BMPString:
1070+
return UTF_16BE;
1071+
case DerValue.tag_UTF8String:
1072+
return UTF_8;
1073+
default:
1074+
throw new Error("unexpected tag: " + value.tag);
1075+
}
1076+
}
1077+
10291078
boolean hasRFC2253Keyword() {
10301079
return AVAKeyword.hasKeyword(oid, RFC2253);
10311080
}

jdk/test/java/security/testlibrary/CertificateBuilder.java

Lines changed: 24 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,7 @@
5353
import sun.security.x509.SubjectAlternativeNameExtension;
5454
import sun.security.x509.URIName;
5555
import sun.security.x509.KeyIdentifier;
56+
import sun.security.x509.X500Name;
5657

5758
/**
5859
* Helper class that builds and signs X.509 certificates.
@@ -89,7 +90,7 @@
8990
public class CertificateBuilder {
9091
private final CertificateFactory factory;
9192

92-
private X500Principal subjectName = null;
93+
private X500Name subjectName = null;
9394
private BigInteger serialNumber = null;
9495
private PublicKey publicKey = null;
9596
private Date notBefore = null;
@@ -114,17 +115,35 @@ public CertificateBuilder() throws CertificateException {
114115
* @param name An {@link X500Principal} to be used as the subject name
115116
* on this certificate.
116117
*/
117-
public void setSubjectName(X500Principal name) {
118-
subjectName = name;
118+
public CertificateBuilder setSubjectName(X500Principal name) {
119+
subjectName = X500Name.asX500Name(name);
120+
return this;
119121
}
120122

121123
/**
122124
* Set the subject name for the certificate.
123125
*
124126
* @param name The subject name in RFC 2253 format
125127
*/
126-
public void setSubjectName(String name) {
127-
subjectName = new X500Principal(name);
128+
public CertificateBuilder setSubjectName(String name) {
129+
try {
130+
subjectName = new X500Name(name);
131+
} catch (IOException ioe) {
132+
throw new IllegalArgumentException(ioe);
133+
}
134+
return this;
135+
}
136+
137+
/**
138+
* Set the subject name for the certificate. This method is useful when
139+
* you need more control over the contents of the subject name.
140+
*
141+
* @param name an {@code X500Name} to be used as the subject name
142+
* on this certificate
143+
*/
144+
public CertificateBuilder setSubjectName(X500Name name) {
145+
subjectName = name;
146+
return this;
128147
}
129148

130149
/**

0 commit comments

Comments
 (0)