001/* 002 * acme4j - Java ACME client 003 * 004 * Copyright (C) 2015 Richard "Shred" Körber 005 * http://acme4j.shredzone.org 006 * 007 * Licensed under the Apache License, Version 2.0 (the "License"); 008 * you may not use this file except in compliance with the License. 009 * 010 * This program is distributed in the hope that it will be useful, 011 * but WITHOUT ANY WARRANTY; without even the implied warranty of 012 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 013 */ 014package org.shredzone.acme4j.util; 015 016import java.io.IOException; 017import java.io.InputStream; 018import java.io.InputStreamReader; 019import java.io.OutputStream; 020import java.io.OutputStreamWriter; 021import java.io.Writer; 022import java.security.cert.CertificateException; 023import java.security.cert.CertificateFactory; 024import java.security.cert.X509Certificate; 025 026import org.bouncycastle.openssl.PEMParser; 027import org.bouncycastle.openssl.jcajce.JcaPEMWriter; 028import org.bouncycastle.pkcs.PKCS10CertificationRequest; 029import org.shredzone.acme4j.Certificate; 030 031/** 032 * Utility class offering convenience methods for certificates. 033 * <p> 034 * Requires {@code Bouncy Castle}. This class is part of the {@code acme4j-utils} module. 035 */ 036public final class CertificateUtils { 037 038 private CertificateUtils() { 039 // utility class without constructor 040 } 041 042 /** 043 * Reads an {@link X509Certificate} PEM file from an {@link InputStream}. 044 * 045 * @param in 046 * {@link InputStream} to read the certificate from. The 047 * {@link InputStream} is closed after use. 048 * @return {@link X509Certificate} that was read 049 */ 050 public static X509Certificate readX509Certificate(InputStream in) throws IOException { 051 try (InputStream uin = in) { 052 CertificateFactory certificateFactory = CertificateFactory.getInstance("X.509"); 053 return (X509Certificate) certificateFactory.generateCertificate(uin); 054 } catch (CertificateException ex) { 055 throw new IOException(ex); 056 } 057 } 058 059 /** 060 * Writes an X.509 certificate PEM file. 061 * 062 * @param cert 063 * {@link X509Certificate} to write 064 * @param out 065 * {@link OutputStream} to write the PEM file to. The {@link OutputStream} 066 * is closed after use. 067 */ 068 public static void writeX509Certificate(X509Certificate cert, OutputStream out) throws IOException { 069 writeX509Certificate(cert, new OutputStreamWriter(out, "utf-8")); 070 } 071 072 /** 073 * Writes an X.509 certificate PEM file. 074 * 075 * @param cert 076 * {@link X509Certificate} to write 077 * @param w 078 * {@link Writer} to write the PEM file to. The {@link Writer} is closed 079 * after use. 080 */ 081 public static void writeX509Certificate(X509Certificate cert, Writer w) throws IOException { 082 writeX509Certificates(w, cert); 083 } 084 085 /** 086 * Writes a X.509 certificate chain to a PEM file. 087 * 088 * @param w 089 * {@link Writer} to write the certificate chain to. The {@link Writer} is 090 * closed after use. 091 * @param cert 092 * {@link X509Certificate} to write, {@code null} to skip this certificate 093 * @param chain 094 * {@link X509Certificate} chain to add to the certificate. {@code null} 095 * values are ignored, array may be empty. 096 * @deprecated use {@link Certificate#downloadFullChain()} and 097 * {@link #writeX509Certificates(Writer, X509Certificate[])} instead 098 */ 099 @Deprecated 100 public static void writeX509CertificateChain(Writer w, X509Certificate cert, X509Certificate... chain) 101 throws IOException { 102 X509Certificate[] certs = new X509Certificate[chain.length + 1]; 103 certs[0] = cert; 104 System.arraycopy(chain, 0, certs, 1, chain.length); 105 writeX509Certificates(w, certs); 106 } 107 108 /** 109 * Writes multiple X.509 certificates to a PEM file. 110 * 111 * @param w 112 * {@link Writer} to write the certificate chain to. The {@link Writer} is 113 * closed after use. 114 * @param certs 115 * {@link X509Certificate} certificates to add to the certificate. 116 * {@code null} values are ignored, array may be empty. 117 * @since 1.1 118 */ 119 public static void writeX509Certificates(Writer w, X509Certificate... certs) 120 throws IOException { 121 try (JcaPEMWriter jw = new JcaPEMWriter(w)) { 122 for (X509Certificate c : certs) { 123 if (c != null) { 124 jw.writeObject(c); 125 } 126 } 127 } 128 } 129 130 /** 131 * Reads a CSR PEM file. 132 * 133 * @param in 134 * {@link InputStream} to read the CSR from. The {@link InputStream} is 135 * closed after use. 136 * @return CSR that was read 137 */ 138 public static PKCS10CertificationRequest readCSR(InputStream in) throws IOException { 139 try (PEMParser pemParser = new PEMParser(new InputStreamReader(in))) { 140 Object parsedObj = pemParser.readObject(); 141 if (!(parsedObj instanceof PKCS10CertificationRequest)) { 142 throw new IOException("Not a PKCS10 CSR"); 143 } 144 return (PKCS10CertificationRequest) parsedObj; 145 } 146 } 147 148}