]> WPIA git - gigi.git/blob - src/club/wpia/gigi/util/CertExporter.java
chg: add p7b to download all intermediate certificates in one file
[gigi.git] / src / club / wpia / gigi / util / CertExporter.java
1 package club.wpia.gigi.util;
2
3 import java.io.IOException;
4 import java.io.OutputStream;
5 import java.math.BigInteger;
6 import java.security.GeneralSecurityException;
7 import java.security.cert.CRLException;
8 import java.security.cert.CertificateEncodingException;
9 import java.security.cert.CertificateException;
10 import java.security.cert.X509CRL;
11 import java.security.cert.X509Certificate;
12 import java.util.HashSet;
13 import java.util.LinkedList;
14 import java.util.Set;
15
16 import javax.servlet.ServletOutputStream;
17
18 import club.wpia.gigi.GigiApiException;
19 import club.wpia.gigi.dbObjects.CACertificate;
20 import club.wpia.gigi.dbObjects.Certificate;
21 import sun.security.pkcs.ContentInfo;
22 import sun.security.pkcs.PKCS7;
23 import sun.security.pkcs.SignerInfo;
24 import sun.security.util.DerOutputStream;
25 import sun.security.util.DerValue;
26 import sun.security.x509.AlgorithmId;
27 import sun.security.x509.X509CRLImpl;
28 import sun.security.x509.X509CertImpl;
29
30 public class CertExporter {
31
32     private CertExporter() {}
33
34     public static void writeCertCrt(Certificate c, ServletOutputStream out, boolean doChain, boolean includeAnchor, boolean includeLeaf) throws IOException, GeneralSecurityException, GigiApiException {
35         X509Certificate cert = c.cert();
36         if (includeLeaf) {
37             out.println(PEM.encode("CERTIFICATE", cert.getEncoded()));
38         }
39         if (doChain) {
40             CACertificate ca = c.getParent();
41             while ( !ca.isSelfsigned()) {
42                 out.println(PEM.encode("CERTIFICATE", ca.getCertificate().getEncoded()));
43                 ca = ca.getParent();
44             }
45             if (includeAnchor) {
46                 out.println(PEM.encode("CERTIFICATE", ca.getCertificate().getEncoded()));
47             }
48         }
49     }
50
51     public static void writeCertCer(Certificate c, ServletOutputStream out, boolean doChain, boolean includeAnchor) throws IOException, GeneralSecurityException, GigiApiException {
52         X509Certificate cert = c.cert();
53         if (doChain) {
54             PKCS7 p7 = toP7Chain(c);
55             p7.encodeSignedData(out);
56         } else {
57             out.write(cert.getEncoded());
58         }
59     }
60
61     private static PKCS7 toP7Chain(Certificate c) throws IOException, GeneralSecurityException, GigiApiException {
62
63         return generateP7Bundle(getChain(c));
64
65     }
66
67     private static PKCS7 generateP7Bundle(LinkedList<X509Certificate> ll) {
68         PKCS7 p7 = new PKCS7(new AlgorithmId[0], new ContentInfo(ContentInfo.DATA_OID, null), ll.toArray(new X509Certificate[ll.size()]), new SignerInfo[0]) {
69
70             @Override
71             public void encodeSignedData(DerOutputStream out) throws IOException {
72                 DerOutputStream signedData = new DerOutputStream();
73                 BigInteger version = getVersion();
74                 AlgorithmId[] digestAlgorithmIds = getDigestAlgorithmIds();
75                 ContentInfo contentInfo = getContentInfo();
76                 X509Certificate[] certificates = getCertificates();
77                 X509CRL[] crls = getCRLs();
78                 SignerInfo[] signerInfos = getSignerInfos();
79
80                 // version
81                 signedData.putInteger(version);
82
83                 // digestAlgorithmIds
84                 signedData.putOrderedSetOf(DerValue.tag_Set, digestAlgorithmIds);
85
86                 // contentInfo
87                 contentInfo.encode(signedData);
88
89                 // certificates (optional)
90                 if (certificates != null && certificates.length != 0) {
91                     DerOutputStream sub = new DerOutputStream();
92                     // cast to X509CertImpl[] since X509CertImpl implements
93                     // DerEncoder
94                     X509CertImpl implCerts[] = new X509CertImpl[certificates.length];
95                     for (int i = 0; i < certificates.length; i++) {
96                         try {
97                             sub.write(certificates[i].getEncoded());
98                         } catch (CertificateEncodingException e) {
99                             sub.close();
100                             throw new IOException(e);
101                         }
102                         if (certificates[i] instanceof X509CertImpl) {
103                             implCerts[i] = (X509CertImpl) certificates[i];
104                         } else {
105                             try {
106                                 byte[] encoded = certificates[i].getEncoded();
107                                 implCerts[i] = new X509CertImpl(encoded);
108                             } catch (CertificateException ce) {
109                                 sub.close();
110                                 throw new IOException(ce);
111                             }
112                         }
113                     }
114
115                     // Add the certificate set (tagged with [0] IMPLICIT)
116                     // to the signed data
117                     signedData.write((byte) 0xA0, sub);
118                     sub.close();
119                 }
120
121                 // CRLs (optional)
122                 if (crls != null && crls.length != 0) {
123                     // cast to X509CRLImpl[] since X509CRLImpl implements
124                     // DerEncoder
125                     Set<X509CRLImpl> implCRLs = new HashSet<X509CRLImpl>(crls.length);
126                     for (X509CRL crl : crls) {
127                         if (crl instanceof X509CRLImpl) {
128                             implCRLs.add((X509CRLImpl) crl);
129                         } else {
130                             try {
131                                 byte[] encoded = crl.getEncoded();
132                                 implCRLs.add(new X509CRLImpl(encoded));
133                             } catch (CRLException ce) {
134                                 throw new IOException(ce);
135                             }
136                         }
137                     }
138
139                     // Add the CRL set (tagged with [1] IMPLICIT)
140                     // to the signed data
141                     signedData.putOrderedSetOf((byte) 0xA1, implCRLs.toArray(new X509CRLImpl[implCRLs.size()]));
142                 }
143
144                 // signerInfos
145                 signedData.putOrderedSetOf(DerValue.tag_Set, signerInfos);
146
147                 // making it a signed data block
148                 DerValue signedDataSeq = new DerValue(DerValue.tag_Sequence, signedData.toByteArray());
149
150                 // making it a content info sequence
151                 ContentInfo block = new ContentInfo(ContentInfo.SIGNED_DATA_OID, signedDataSeq);
152
153                 // writing out the contentInfo sequence
154                 block.encode(out);
155             }
156
157         };
158         return p7;
159     }
160
161     private static LinkedList<X509Certificate> getChain(Certificate c) throws IOException, GeneralSecurityException, GigiApiException {
162         LinkedList<X509Certificate> ll = new LinkedList<>();
163         ll.add(c.cert());
164         CACertificate ca = c.getParent();
165         while ( !ca.isSelfsigned()) {
166             ll.add(ca.getCertificate());
167             ca = ca.getParent();
168         }
169         ll.add(ca.getCertificate());
170         return ll;
171     }
172
173     public static void writeCertBundle(OutputStream out) throws IOException, GeneralSecurityException, GigiApiException {
174
175         CACertificate[] cs = CACertificate.getAll();
176         LinkedList<X509Certificate> ll = new LinkedList<>();
177         for (CACertificate cb : cs) {
178             if ( !cb.isSelfsigned()) {
179                 ll.add(cb.getCertificate());
180             }
181         }
182
183         PKCS7 p7 = generateP7Bundle(ll);
184         p7.encodeSignedData(out);
185     }
186 }