summaryrefslogtreecommitdiffstats
path: root/security-utils/src/main/java/com/yahoo/security/X509CertificateUtils.java
diff options
context:
space:
mode:
authorgjoranv <gjoranv@gmail.com>2018-10-19 10:47:54 +0200
committerGitHub <noreply@github.com>2018-10-19 10:47:54 +0200
commit5ac10d9e9c036d0448ebd4e1ff9d3704a675b69e (patch)
treeeaf25ba520a44df4ddf7244024f9e5072f676a4b /security-utils/src/main/java/com/yahoo/security/X509CertificateUtils.java
parent182384b808434b3f449f459f9bce113f0aa5cc16 (diff)
parent1c3999a1faa10d2def03f43ba7ce22bb83997e26 (diff)
Merge pull request #7344 from vespa-engine/bjorncs/security-lib
Move classes in com.yahoo.security to security-utils
Diffstat (limited to 'security-utils/src/main/java/com/yahoo/security/X509CertificateUtils.java')
-rw-r--r--security-utils/src/main/java/com/yahoo/security/X509CertificateUtils.java136
1 files changed, 136 insertions, 0 deletions
diff --git a/security-utils/src/main/java/com/yahoo/security/X509CertificateUtils.java b/security-utils/src/main/java/com/yahoo/security/X509CertificateUtils.java
new file mode 100644
index 00000000000..33bd750bac5
--- /dev/null
+++ b/security-utils/src/main/java/com/yahoo/security/X509CertificateUtils.java
@@ -0,0 +1,136 @@
+// Copyright 2018 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+package com.yahoo.security;
+
+import org.bouncycastle.asn1.ASN1Encodable;
+import org.bouncycastle.asn1.ASN1OctetString;
+import org.bouncycastle.asn1.ASN1Primitive;
+import org.bouncycastle.asn1.x509.GeneralNames;
+import org.bouncycastle.cert.X509CertificateHolder;
+import org.bouncycastle.cert.jcajce.JcaX509CertificateConverter;
+import org.bouncycastle.openssl.PEMParser;
+import org.bouncycastle.openssl.jcajce.JcaPEMWriter;
+import org.bouncycastle.util.io.pem.PemObject;
+
+import javax.naming.NamingException;
+import javax.naming.ldap.LdapName;
+import javax.security.auth.x500.X500Principal;
+import java.io.IOException;
+import java.io.StringReader;
+import java.io.StringWriter;
+import java.io.UncheckedIOException;
+import java.security.GeneralSecurityException;
+import java.security.cert.CertificateException;
+import java.security.cert.X509Certificate;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+import static com.yahoo.security.Extension.SUBJECT_ALTERNATIVE_NAMES;
+import static java.util.stream.Collectors.toList;
+
+/**
+ * @author bjorncs
+ */
+public class X509CertificateUtils {
+
+ private X509CertificateUtils() {}
+
+ public static X509Certificate fromPem(String pem) {
+ try (PEMParser parser = new PEMParser(new StringReader(pem))) {
+ return toX509Certificate(parser.readObject());
+ } catch (IOException e) {
+ throw new UncheckedIOException(e);
+ } catch (CertificateException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ public static List<X509Certificate> certificateListFromPem(String pem) {
+ try (PEMParser parser = new PEMParser(new StringReader(pem))) {
+ List<X509Certificate> list = new ArrayList<>();
+ Object pemObject;
+ while ((pemObject = parser.readObject()) != null) {
+ list.add(toX509Certificate(pemObject));
+ }
+ return list;
+ } catch (IOException e) {
+ throw new UncheckedIOException(e);
+ } catch (CertificateException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ private static X509Certificate toX509Certificate(Object pemObject) throws CertificateException {
+ if (pemObject instanceof X509Certificate) {
+ return (X509Certificate) pemObject;
+ }
+ if (pemObject instanceof X509CertificateHolder) {
+ return new JcaX509CertificateConverter()
+ .setProvider(BouncyCastleProviderHolder.getInstance())
+ .getCertificate((X509CertificateHolder) pemObject);
+ }
+ throw new IllegalArgumentException("Invalid type of PEM object: " + pemObject);
+ }
+
+ public static String toPem(X509Certificate certificate) {
+ try (StringWriter stringWriter = new StringWriter(); JcaPEMWriter pemWriter = new JcaPEMWriter(stringWriter)) {
+ pemWriter.writeObject(new PemObject("CERTIFICATE", certificate.getEncoded()));
+ pemWriter.flush();
+ return stringWriter.toString();
+ } catch (GeneralSecurityException e) {
+ throw new RuntimeException(e);
+ } catch (IOException e) {
+ throw new UncheckedIOException(e);
+ }
+ }
+
+ public static String toPem(List<X509Certificate> certificates) {
+ try (StringWriter stringWriter = new StringWriter(); JcaPEMWriter pemWriter = new JcaPEMWriter(stringWriter)) {
+ for (X509Certificate certificate : certificates) {
+ pemWriter.writeObject(new PemObject("CERTIFICATE", certificate.getEncoded()));
+ }
+ pemWriter.flush();
+ return stringWriter.toString();
+ } catch (GeneralSecurityException e) {
+ throw new RuntimeException(e);
+ } catch (IOException e) {
+ throw new UncheckedIOException(e);
+ }
+ }
+
+ public static List<String> getSubjectCommonNames(X509Certificate certificate) {
+ return getCommonNames(certificate.getSubjectX500Principal());
+ }
+
+ public static List<String> getIssuerCommonNames(X509Certificate certificate) {
+ return getCommonNames(certificate.getIssuerX500Principal());
+ }
+
+ public static List<String> getCommonNames(X500Principal subject) {
+ try {
+ String subjectPrincipal = subject.getName();
+ return new LdapName(subjectPrincipal).getRdns().stream()
+ .filter(rdn -> rdn.getType().equalsIgnoreCase("cn"))
+ .map(rdn -> rdn.getValue().toString())
+ .collect(toList());
+ } catch (NamingException e) {
+ throw new IllegalArgumentException("Invalid CN: " + e, e);
+ }
+
+ }
+
+ public static List<SubjectAlternativeName> getSubjectAlternativeNames(X509Certificate certificate) {
+ try {
+ byte[] extensionValue = certificate.getExtensionValue(SUBJECT_ALTERNATIVE_NAMES.getOId());
+ if (extensionValue == null) return Collections.emptyList();
+ ASN1Encodable asn1Encodable = ASN1Primitive.fromByteArray(extensionValue);
+ if (asn1Encodable instanceof ASN1OctetString) {
+ asn1Encodable = ASN1Primitive.fromByteArray(((ASN1OctetString) asn1Encodable).getOctets());
+ }
+ GeneralNames names = GeneralNames.getInstance(asn1Encodable);
+ return SubjectAlternativeName.fromGeneralNames(names);
+ } catch (IOException e) {
+ throw new UncheckedIOException(e);
+ }
+ }
+}