View Javadoc
1   /*
2    * Copyright 2014 The Netty Project
3    *
4    * The Netty Project licenses this file to you under the Apache License,
5    * version 2.0 (the "License"); you may not use this file except in compliance
6    * with the License. You may obtain a copy of the License at:
7    *
8    *   https://www.apache.org/licenses/LICENSE-2.0
9    *
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
12   * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
13   * License for the specific language governing permissions and limitations
14   * under the License.
15   */
16  
17  package io.netty.handler.ssl.util;
18  
19  import io.netty.util.internal.SuppressJava6Requirement;
20  import sun.security.x509.AlgorithmId;
21  import sun.security.x509.CertificateAlgorithmId;
22  import sun.security.x509.CertificateIssuerName;
23  import sun.security.x509.CertificateSerialNumber;
24  import sun.security.x509.CertificateSubjectName;
25  import sun.security.x509.CertificateValidity;
26  import sun.security.x509.CertificateVersion;
27  import sun.security.x509.CertificateX509Key;
28  import sun.security.x509.X500Name;
29  import sun.security.x509.X509CertImpl;
30  import sun.security.x509.X509CertInfo;
31  
32  import java.util.Date;
33  import java.math.BigInteger;
34  import java.security.KeyPair;
35  import java.security.PrivateKey;
36  import java.security.SecureRandom;
37  import java.security.cert.CertificateException;
38  
39  import static io.netty.handler.ssl.util.SelfSignedCertificate.*;
40  
41  /**
42   * Generates a self-signed certificate using {@code sun.security.x509} package provided by OpenJDK.
43   */
44  final class OpenJdkSelfSignedCertGenerator {
45  
46      @SuppressJava6Requirement(reason = "Usage guarded by dependency check")
47      static String[] generate(String fqdn, KeyPair keypair, SecureRandom random, Date notBefore, Date notAfter,
48                               String algorithm) throws Exception {
49          PrivateKey key = keypair.getPrivate();
50  
51          // Prepare the information required for generating an X.509 certificate.
52          X509CertInfo info = new X509CertInfo();
53          X500Name owner = new X500Name("CN=" + fqdn);
54          info.set(X509CertInfo.VERSION, new CertificateVersion(CertificateVersion.V3));
55          info.set(X509CertInfo.SERIAL_NUMBER, new CertificateSerialNumber(new BigInteger(64, random)));
56          try {
57              info.set(X509CertInfo.SUBJECT, new CertificateSubjectName(owner));
58          } catch (CertificateException ignore) {
59              info.set(X509CertInfo.SUBJECT, owner);
60          }
61          try {
62              info.set(X509CertInfo.ISSUER, new CertificateIssuerName(owner));
63          } catch (CertificateException ignore) {
64              info.set(X509CertInfo.ISSUER, owner);
65          }
66          info.set(X509CertInfo.VALIDITY, new CertificateValidity(notBefore, notAfter));
67          info.set(X509CertInfo.KEY, new CertificateX509Key(keypair.getPublic()));
68          info.set(X509CertInfo.ALGORITHM_ID,
69                  // sha256WithRSAEncryption
70                  new CertificateAlgorithmId(AlgorithmId.get("1.2.840.113549.1.1.11")));
71  
72          // Sign the cert to identify the algorithm that's used.
73          X509CertImpl cert = new X509CertImpl(info);
74          cert.sign(key, algorithm.equalsIgnoreCase("EC") ? "SHA256withECDSA" : "SHA256withRSA");
75  
76          // Update the algorithm and sign again.
77          info.set(CertificateAlgorithmId.NAME + '.' + CertificateAlgorithmId.ALGORITHM, cert.get(X509CertImpl.SIG_ALG));
78          cert = new X509CertImpl(info);
79          cert.sign(key, algorithm.equalsIgnoreCase("EC") ? "SHA256withECDSA" : "SHA256withRSA");
80          cert.verify(keypair.getPublic());
81  
82          return newSelfSignedCertificate(fqdn, key, cert);
83      }
84  
85      private OpenJdkSelfSignedCertGenerator() { }
86  }