Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

8311546: Certificate name constraints improperly validated with leading period #3149

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 3 additions & 9 deletions src/java.base/share/classes/sun/security/x509/DNSName.java
Original file line number Diff line number Diff line change
Expand Up @@ -202,18 +202,12 @@ public int hashCode() {
* </ul>. These results are used in checking NameConstraints during
* certification path verification.
* <p>
* RFC5280: DNS name restrictions are expressed as host.example.com.
* RFC5280: For DNS names, restrictions MUST use the DNSName syntax in Section 4.2.1.6.
* Any DNS name that can be constructed by simply adding zero or more
* labels to the left-hand side of the name satisfies the name constraint.
* For example, www.host.example.com would satisfy the constraint but
* host1.example.com would not.
* <p>
* RFC 5280: DNSName restrictions are expressed as foo.bar.com.
* Any DNSName that
* can be constructed by simply adding to the left hand side of the name
* satisfies the name constraint. For example, www.foo.bar.com would
* satisfy the constraint but foo1.bar.com would not.
* <p>
* RFC1034: By convention, domain names can be stored with arbitrary case, but
* domain name comparisons for all present domain functions are done in a
* case-insensitive manner, assuming an ASCII character set, and a high
Expand All @@ -238,13 +232,13 @@ else if (inputName.getType() != NAME_DNS)
constraintType = NAME_MATCH;
else if (thisName.endsWith(inName)) {
int inNdx = thisName.lastIndexOf(inName);
if (thisName.charAt(inNdx-1) == '.' )
if (thisName.charAt(inNdx-1) == '.' ^ inName.charAt(0) == '.')
constraintType = NAME_WIDENS;
else
constraintType = NAME_SAME_TYPE;
} else if (inName.endsWith(thisName)) {
int ndx = inName.lastIndexOf(thisName);
if (inName.charAt(ndx-1) == '.' )
if (inName.charAt(ndx-1) == '.' ^ thisName.charAt(0) == '.')
constraintType = NAME_NARROWS;
else
constraintType = NAME_SAME_TYPE;
Expand Down
112 changes: 112 additions & 0 deletions test/jdk/sun/security/x509/DNSName/LeadingPeriod.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,112 @@
/*
* Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* 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.
*/

/*
* @test
* @bug 8311546
* @summary Adopt de-facto standards on x509 Name Constraints with leading dot. Certs
* can be generated by running generate-certs.sh
* @library /test/lib
* @modules java.base/sun.security.x509
*/

import java.io.*;
import java.nio.file.*;
import java.util.*;
import java.security.Security;
import java.security.cert.*;

public class LeadingPeriod {

private static CertPath makeCertPath(String targetCertStr,
PKIXParameters params) throws CertificateException {
// generate certificate from cert strings
CertificateFactory cf = CertificateFactory.getInstance("X.509");

ByteArrayInputStream is;

is = new ByteArrayInputStream(targetCertStr.getBytes());
Certificate targetCert = cf.generateCertificate(is);
// set validity date so that validation won't fail when cert expires
params.setDate(((X509Certificate)targetCert).getNotBefore());

// generate certification path
List<Certificate> list = List.of(targetCert);

return cf.generateCertPath(list);
}

private static PKIXParameters genParams(String caStr) throws Exception {
// generate certificate from cert string
CertificateFactory cf = CertificateFactory.getInstance("X.509");

ByteArrayInputStream is = new ByteArrayInputStream(caStr.getBytes());
Certificate selfSignedCert = cf.generateCertificate(is);

// generate a trust anchor
TrustAnchor anchor = new TrustAnchor((X509Certificate) selfSignedCert, null);

Set<TrustAnchor> anchors = Collections.singleton(anchor);

PKIXParameters params = new PKIXParameters(anchors);

// disable certificate revocation checking
params.setRevocationEnabled(false);

return params;
}

public static void main(String[] args) throws Exception {

CertPathValidator validator = CertPathValidator.getInstance("PKIX");

// Load certs with a NameConstraint where DNS value does not begin with a period
Path targetFromCAWithoutPeriodPath = Paths.get(System.getProperty(
"test.src", "./") + "/certs/withoutLeadingPeriod/leaf.pem");
String targetFromCAWithoutPeriod = Files.readString(targetFromCAWithoutPeriodPath);

Path caWithoutLeadingPeriodPath = Paths.get(System.getProperty(
"test.src", "./") + "/certs/withoutLeadingPeriod/ca.pem");
String caWithoutLeadingPeriod = Files.readString(caWithoutLeadingPeriodPath);

PKIXParameters paramsForCAWithoutLeadingPeriod = genParams(caWithoutLeadingPeriod);
CertPath pathWithoutLeadingPeriod = makeCertPath(
targetFromCAWithoutPeriod, paramsForCAWithoutLeadingPeriod);

validator.validate(pathWithoutLeadingPeriod, paramsForCAWithoutLeadingPeriod);

// Load certificates with a NameConstraint where the DNS value does begin with a period
Path targetFromCAWithPeriodPath = Paths.get(System.getProperty(
"test.src", "./") + "/certs/withLeadingPeriod/leaf.pem");
String targetFromCAWithPeriod = Files.readString(targetFromCAWithPeriodPath);

Path caWithLeadingPeriodPath = Paths.get(System.getProperty(
"test.src", "./") + "/certs/withLeadingPeriod/ca.pem");
String caWithLeadingPeriod = Files.readString(caWithLeadingPeriodPath);

PKIXParameters paramsForCAWithLeadingPeriod = genParams(caWithLeadingPeriod);
CertPath pathWithLeadingPeriod = makeCertPath(targetFromCAWithPeriod, paramsForCAWithLeadingPeriod);

validator.validate(pathWithLeadingPeriod, paramsForCAWithLeadingPeriod);
}
}
91 changes: 91 additions & 0 deletions test/jdk/sun/security/x509/DNSName/certs/generate-certs.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
#!/usr/bin/env bash

set -e

###############################################################
# CA with a leading period in the name constraint #
###############################################################
mkdir -p withLeadingPeriod

openssl req \
-newkey rsa:1024 \
-keyout withLeadingPeriod/ca.key \
-out withLeadingPeriod/ca.csr \
-subj "/C=US/O=Example/CN=Example CA with period" \
-nodes

openssl x509 \
-req \
-in withLeadingPeriod/ca.csr \
-extfile openssl.cnf \
-extensions withLeadingPeriod \
-signkey withLeadingPeriod/ca.key \
-out withLeadingPeriod/ca.pem

# leaf certificate
openssl req \
-newkey rsa:1024 \
-keyout withLeadingPeriod/leaf.key \
-out withLeadingPeriod/leaf.csr \
-subj '/CN=demo.example.com' \
-addext 'subjectAltName = DNS:demo.example.com' \
-nodes

openssl x509 \
-req \
-in withLeadingPeriod/leaf.csr \
-CAcreateserial \
-CA withLeadingPeriod/ca.pem \
-CAkey withLeadingPeriod/ca.key \
-out withLeadingPeriod/leaf.pem


# ##################################################################
# # CA without a leading period in the name contraint #
# ##################################################################
mkdir -p withoutLeadingPeriod

openssl req \
-newkey rsa:1024 \
-keyout withoutLeadingPeriod/ca.key \
-out withoutLeadingPeriod/ca.csr \
-subj "/C=US/O=Example/CN=Example CA without period" \
-nodes

openssl x509 \
-req \
-in withoutLeadingPeriod/ca.csr \
-extfile openssl.cnf \
-extensions withoutLeadingPeriod \
-signkey withoutLeadingPeriod/ca.key \
-out withoutLeadingPeriod/ca.pem

# leaf certificate
openssl req \
-newkey rsa:1024 \
-keyout withoutLeadingPeriod/leaf.key \
-out withoutLeadingPeriod/leaf.csr \
-subj '/CN=demo.example.com' \
-addext 'subjectAltName = DNS:demo.example.com' \
-nodes

openssl x509 \
-req \
-in withoutLeadingPeriod/leaf.csr \
-CAcreateserial \
-CA withoutLeadingPeriod/ca.pem \
-CAkey withoutLeadingPeriod/ca.key \
-out withoutLeadingPeriod/leaf.pem


# # Verify both leaf certificates

set +e
openssl verify \
-CAfile withLeadingPeriod/ca.pem \
withLeadingPeriod/leaf.pem

openssl verify \
-CAfile withoutLeadingPeriod/ca.pem \
withoutLeadingPeriod/leaf.pem

40 changes: 40 additions & 0 deletions test/jdk/sun/security/x509/DNSName/certs/openssl.cnf
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
#
# OpenSSL configuration file.
#

[ withLeadingPeriod ]
subjectKeyIdentifier = hash
authorityKeyIdentifier = keyid:always,issuer
basicConstraints = critical,CA:true
keyUsage = critical,keyCertSign
nameConstraints = critical,permitted;DNS:.example.com

[ withoutLeadingPeriod ]
subjectKeyIdentifier = hash
authorityKeyIdentifier = keyid:always,issuer
basicConstraints = critical,CA:true
keyUsage = critical,keyCertSign
nameConstraints = critical,permitted;DNS:example.com

[ v3_ca ]
subjectKeyIdentifier = hash
authorityKeyIdentifier = keyid:always,issuer
basicConstraints = critical,CA:true
keyUsage = critical,keyCertSign


[req]
distinguished_name = req_distinguished_name
x509_extensions = v3_ca # The extentions to add to self signed certs
req_extensions = v3_req # The extensions to add to req's

prompt = no

[req_distinguished_name]
C = US
O = Example
CN = example.com

[v3_req]
keyUsage = keyEncipherment, dataEncipherment
extendedKeyUsage = serverAuth
16 changes: 16 additions & 0 deletions test/jdk/sun/security/x509/DNSName/certs/withLeadingPeriod/ca.pem
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
-----BEGIN CERTIFICATE-----
MIICgzCCAeygAwIBAgIJANBGv+BGZZHtMA0GCSqGSIb3DQEBCwUAMEAxCzAJBgNV
BAYTAlVTMRAwDgYDVQQKDAdFeGFtcGxlMR8wHQYDVQQDDBZFeGFtcGxlIENBIHdp
dGggcGVyaW9kMB4XDTIzMTAxOTIwNTE0NVoXDTIzMTExODIwNTE0NVowQDELMAkG
A1UEBhMCVVMxEDAOBgNVBAoMB0V4YW1wbGUxHzAdBgNVBAMMFkV4YW1wbGUgQ0Eg
d2l0aCBwZXJpb2QwgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBAPfaISk+Dvzk
m3AY7IDZYrGWpwxHciacalrsrOFl3mj3FQ/kVhofDri3mE7bxNKWyHNcbt+Cteck
TsGKBH85QsIifju7hqlrR+UbYtQF9/REkxX72gzim4xGk9KmKkuGpT5aZgvTE5eg
ZumJ9XxCjGn5nbsdJoqAE/9B96GqXJvlAgMBAAGjgYQwgYEwHQYDVR0OBBYEFG8h
vtka47iFUsc+3wmQ3LQRXUv3MB8GA1UdIwQYMBaAFG8hvtka47iFUsc+3wmQ3LQR
XUv3MA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgIEMB4GA1UdHgEB/wQU
MBKgEDAOggwuZXhhbXBsZS5jb20wDQYJKoZIhvcNAQELBQADgYEAkPeCbKokI067
Dt2bommouO7LhTXivjMsByfZs8i9LZUVJz5Is+mDC36nLy4U3+QhofRLlEkWyOlE
033xBtm4YPsazpur79PJtvZemV0KwwMtKCoJYNlcy2llmdKjUwe4PsPnJPqH2KL5
Cxios1gil8XL5OCmEUSCT9uBblh+9gk=
-----END CERTIFICATE-----
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
-----BEGIN CERTIFICATE-----
MIIB0jCCATsCCQCgOCS7vOUOXTANBgkqhkiG9w0BAQsFADBAMQswCQYDVQQGEwJV
UzEQMA4GA1UECgwHRXhhbXBsZTEfMB0GA1UEAwwWRXhhbXBsZSBDQSB3aXRoIHBl
cmlvZDAeFw0yMzEwMTkyMDUxNDVaFw0yMzExMTgyMDUxNDVaMBsxGTAXBgNVBAMM
EGRlbW8uZXhhbXBsZS5jb20wgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBALxi
O4r50rNBbHu/blOSRfo9Vqei+QFS7fPwme68FOcvG+uYXf7zluO59V+8O4RPO+ZJ
W6meZvtpOCWFvlSMhBLTRz350LuSPWF+/tnbiyEv487Vi6Tp7kxJytIcMtH/sWkw
hF0Og8YYt3Xm2aLYPxZHGkvOccjau5X1xG1YiULzAgMBAAEwDQYJKoZIhvcNAQEL
BQADgYEA8OXnFO3yZSVmQfYvC2o9amYa7tNUPHgvEjp7xDlPkvL5zF+n8k0hT0kt
pv4BXzRqVIWsZcNi3H1wk6LMeUXi8EWCOR6gclWI0wZkWBhtoh8SCd2VJRmcv+zG
EnInCapszNKN05KEzaFOQv0QayILBUGgHTTXOgbEmryLHXg6zik=
-----END CERTIFICATE-----
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
-----BEGIN CERTIFICATE-----
MIICiDCCAfGgAwIBAgIJALUX88nU2b75MA0GCSqGSIb3DQEBCwUAMEMxCzAJBgNV
BAYTAlVTMRAwDgYDVQQKDAdFeGFtcGxlMSIwIAYDVQQDDBlFeGFtcGxlIENBIHdp
dGhvdXQgcGVyaW9kMB4XDTIzMTAxOTIwNTE0NVoXDTIzMTExODIwNTE0NVowQzEL
MAkGA1UEBhMCVVMxEDAOBgNVBAoMB0V4YW1wbGUxIjAgBgNVBAMMGUV4YW1wbGUg
Q0Egd2l0aG91dCBwZXJpb2QwgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBANmH
HqVoDjgoS60aPhQisqEL3as81tPXxXgnp5M0TE+Lb0z/kXS2mkqYYhzcZneBhVyI
oGTnSnTSh6S1r/gE80x+hH4ZrLZR7jJMRDA9Q7RTOZBNgozS4XnE3AV/EjrIzHJ1
IEt1ezoj2QNdVOv7UHprHGoARl9tdxre4MVUv4S3AgMBAAGjgYMwgYAwHQYDVR0O
BBYEFFG0Mvse4c5C01o8kvKiM4MKMJTCMB8GA1UdIwQYMBaAFFG0Mvse4c5C01o8
kvKiM4MKMJTCMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgIEMB0GA1Ud
HgEB/wQTMBGgDzANggtleGFtcGxlLmNvbTANBgkqhkiG9w0BAQsFAAOBgQC0CKS0
JOR8hfUkZHBo52PrF3IKs33wczH5mfV+HLTdSeKtBD0Vj/7DoT0Yx2k5n6vpwA/x
LTSMC4wUo4hb5164ks45iloU0FrA+n9fWbeqwhQb+DW5MSOgoVLkW+rcdKbDatTO
ENcKZsqiG3aKM7pS7mQa+kUUpXWBUgVnhcsYtQ==
-----END CERTIFICATE-----
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
-----BEGIN CERTIFICATE-----
MIIB1TCCAT4CCQDLscehyPPGXjANBgkqhkiG9w0BAQsFADBDMQswCQYDVQQGEwJV
UzEQMA4GA1UECgwHRXhhbXBsZTEiMCAGA1UEAwwZRXhhbXBsZSBDQSB3aXRob3V0
IHBlcmlvZDAeFw0yMzEwMTkyMDUxNDVaFw0yMzExMTgyMDUxNDVaMBsxGTAXBgNV
BAMMEGRlbW8uZXhhbXBsZS5jb20wgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGB
AMZM9Prp5DkAe4pkLqn4v8DFamMtWVqPlYacJacGzBkuzBn8VNQQw4qnf6wiVHBj
uXLHrUCbldtKFK4XdVukmVyYSLR5BBPxA20fjZcsrBZW7u/14qWmIZW7G0xphezg
6g33qNPq9CPqVHR+IrfEmjWnLjc2KrZ3OQElpJOGp48hAgMBAAEwDQYJKoZIhvcN
AQELBQADgYEAYbIuAQKTXsgaBP3pyMqxPHvklDI7wJjEapbKDsOXYmKMb33pmFSD
ntQFZuOKYNV2rAqQaV/3kiWKyR4vO/gsCfuFeW8kxkhZEXX9CNU0Z6mKcvy274A4
K0gqYGki8hyCc5IMWTUAX2TLdq8W1hwfbjeiNqTY21e+6lIa3kcuLC0=
-----END CERTIFICATE-----