001/* 002 * Licensed to the Apache Software Foundation (ASF) under one 003 * or more contributor license agreements. See the NOTICE file 004 * distributed with this work for additional information 005 * regarding copyright ownership. The ASF licenses this file 006 * to you under the Apache License, Version 2.0 (the 007 * "License"); you may not use this file except in compliance 008 * with the License. You may obtain a copy of the License at 009 * 010 * http://www.apache.org/licenses/LICENSE-2.0 011 * 012 * Unless required by applicable law or agreed to in writing, 013 * software distributed under the License is distributed on an 014 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 015 * KIND, either express or implied. See the License for the 016 * specific language governing permissions and limitations 017 * under the License. 018 */ 019package org.eclipse.aether.generator.sigstore.internal; 020 021import java.io.IOException; 022import java.nio.charset.StandardCharsets; 023import java.security.cert.X509Certificate; 024 025import org.bouncycastle.asn1.ASN1Primitive; 026import org.bouncycastle.asn1.ASN1Sequence; 027import org.bouncycastle.asn1.ASN1String; 028import org.bouncycastle.asn1.DEROctetString; 029 030/** 031 * Helper to decode Fulcio OID data, see <a 032 * href="https://github.com/sigstore/fulcio/blob/main/docs/oid-info.md">Sigstore OID 033 * information</a>. 034 */ 035public class FulcioOidHelper { 036 private static final String SIGSTORE_OID_ROOT = "1.3.6.1.4.1.57264"; 037 private static final String FULCIO_OID_ROOT = SIGSTORE_OID_ROOT + ".1"; 038 039 @Deprecated 040 private static final String FULCIO_ISSUER_OID = FULCIO_OID_ROOT + ".1"; 041 042 private static final String FULCIO_ISSUER_V2_OID = FULCIO_OID_ROOT + ".8"; 043 044 public static String getIssuer(X509Certificate cert) { 045 String issuerV2 = getIssuerV2(cert); 046 if (issuerV2 == null) { 047 return getIssuerV1(cert); 048 } 049 return issuerV2; 050 } 051 052 @Deprecated 053 public static String getIssuerV1(X509Certificate cert) { 054 return getExtensionValue(cert, FULCIO_ISSUER_OID, true); 055 } 056 057 public static String getIssuerV2(X509Certificate cert) { 058 return getExtensionValue(cert, FULCIO_ISSUER_V2_OID, false); 059 } 060 061 /* Extracts the octets from an extension value and converts to utf-8 directly, it does NOT 062 * account for any ASN1 encoded value. If the extension value is an ASN1 object (like an 063 * ASN1 encoded string), you need to write a new extraction helper. */ 064 private static String getExtensionValue(X509Certificate cert, String oid, boolean rawUtf8) { 065 byte[] extensionValue = cert.getExtensionValue(oid); 066 067 if (extensionValue == null) { 068 return null; 069 } 070 try { 071 ASN1Primitive derObject = ASN1Sequence.fromByteArray(cert.getExtensionValue(oid)); 072 if (derObject instanceof DEROctetString) { 073 DEROctetString derOctetString = (DEROctetString) derObject; 074 if (rawUtf8) { 075 // this is unusual, but the octet is a raw utf8 string in fulcio land (no prefix of type) 076 // and not an ASN1 object. 077 return new String(derOctetString.getOctets(), StandardCharsets.UTF_8); 078 } 079 080 derObject = ASN1Sequence.fromByteArray(derOctetString.getOctets()); 081 if (derObject instanceof ASN1String) { 082 ASN1String s = (ASN1String) derObject; 083 return s.getString(); 084 } 085 } 086 throw new RuntimeException( 087 "Could not parse extension " + oid + " in certificate because it was not an octet string"); 088 } catch (IOException ioe) { 089 throw new RuntimeException("Could not parse extension " + oid + " in certificate", ioe); 090 } 091 } 092}