package org.openstack.atlas.util.ca.util;
import java.io.IOException;
import java.math.BigInteger;
import java.net.URI;
import java.security.PublicKey;
import java.security.cert.CertificateEncodingException;
import java.security.cert.CertificateException;
import java.security.cert.CertificateParsingException;
import java.security.cert.X509Certificate;
import java.util.Calendar;
import java.util.Date;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.security.auth.x500.X500Principal;
import org.bouncycastle.asn1.x509.GeneralName;
import org.bouncycastle.asn1.x509.GeneralNames;
import org.bouncycastle.asn1.x509.X509CertificateStructure;
import org.bouncycastle.asn1.x509.X509Name;
import org.bouncycastle.jce.provider.JCERSAPublicKey;
import org.bouncycastle.jce.provider.X509CertificateObject;
import org.openstack.atlas.util.ca.PemUtils;
import org.openstack.atlas.util.ca.exceptions.PemException;
import sun.security.util.ObjectIdentifier;
import sun.security.x509.AuthorityInfoAccessExtension;
import sun.security.x509.X500Name;
import org.bouncycastle.x509.extension.AuthorityKeyIdentifierStructure;
import org.bouncycastle.x509.extension.SubjectKeyIdentifierStructure;
import org.openstack.atlas.util.ca.CertUtils;
import org.openstack.atlas.util.ca.exceptions.NotAnX509CertificateException;
import org.openstack.atlas.util.ca.primitives.RsaConst;
import org.openstack.atlas.util.ca.exceptions.X509ReaderDecodeException;
import org.openstack.atlas.util.ca.exceptions.X509ReaderNoSuchExtensionException;
import sun.security.provider.certpath.OCSP;
import sun.security.x509.AccessDescription;
import sun.security.x509.GeneralNameInterface;
import sun.security.x509.URIName;
import sun.security.x509.X509CertImpl;
public class X509Inspector {
private static final String X500NameFormat = "RFC2253";
private static final String SubjKeyIdOid = "2.5.29.14";
private static final String AuthKeyIdOid = "2.5.29.35";
private X509CertificateObject x509obj;
static {
RsaConst.init();
}
public X509Inspector(X509CertificateObject x509obj) throws NotAnX509CertificateException {
if (x509obj == null) {
String msg = "Resusing to accept null object in "
+ "call to X509Inspector(X509CertificateObject) constructor";
throw new NotAnX509CertificateException();
}
this.x509obj = x509obj;
}
public static X509Inspector newX509Inspector(String x509PemString) throws X509ReaderDecodeException, NotAnX509CertificateException {
String msg;
Object obj;
X509CertificateObject x509obj;
try {
obj = PemUtils.fromPemString(x509PemString);
} catch (PemException ex) {
throw new X509ReaderDecodeException("Error decoding pemString", ex);
}
try {
x509obj = (X509CertificateObject) obj;
} catch (ClassCastException ex) {
msg = String.format("Error casting %s to %s", obj.getClass().getName(), "X509CertificateObject");
throw new X509ReaderDecodeException(msg, ex);
}
return new X509Inspector(x509obj);
}
public static X509Inspector newX509Inspector(X509Certificate x509Cert) throws CertificateEncodingException, CertificateParsingException, NotAnX509CertificateException {
byte[] encoded = x509Cert.getEncoded();
X509CertificateStructure x509Struct = X509CertificateStructure.getInstance(encoded);
X509CertificateObject x509obj = new X509CertificateObject(x509Struct);
X509Inspector x509Reader = new X509Inspector(x509obj);
return x509Reader;
}
// Acts as a don't repeat your self base method. <Rolls Eyes>
private String getCN(X500Principal x500principal) throws IOException {
X500Name x500name = new X500Name(x500principal.getName(X500NameFormat));
String commonName = x500name.getCommonName();
return commonName;
}
public String getSubjectCN() {
X500Principal x500p = x509obj.getSubjectX500Principal();
String cn;
try {
cn = getCN(x500p);
} catch (IOException ex) {
return null;
}
return cn;
}
public URI getOCSPUri() {
URI uri = OCSP.getResponderURI((X509Certificate) x509obj);
if (uri == null) {
return null;
}
return uri;
}
public URI getOCSPCaUri() {
X509CertImpl x509i;
ObjectIdentifier caOid = AccessDescription.Ad_CAISSUERS_Id;
try {
x509i = X509CertImpl.toImpl((X509Certificate) x509obj);
} catch (CertificateException ex) {
return null;
}
AuthorityInfoAccessExtension aiae = x509i.getAuthorityInfoAccessExtension();
if (aiae == null) {
return null;
}
for (AccessDescription des : aiae.getAccessDescriptions()) {
if (des.getAccessMethod().equals(caOid)) {
sun.security.x509.GeneralName generalName = des.getAccessLocation();
if (generalName.getType() == GeneralNameInterface.NAME_URI) {
URIName uriName = (URIName) generalName.getName();
return uriName.getURI();
}
}
}
return null;
}
public String getIssuerName() {
String issuer = x509obj.getIssuerX500Principal().getName(X500NameFormat);
return issuer;
}
public String getSubjectName() {
String subject = x509obj.getSubjectX500Principal().getName(X500NameFormat);
return subject;
}
public String getIssuerCN() {
X500Principal x500p = x509obj.getIssuerX500Principal();
String cn;
try {
cn = getCN(x500p);
} catch (IOException ex) {
return null;
}
return cn;
}
public X509CertificateObject getX509CertificateObject() {
return x509obj;
}
public X509Certificate getX509Certificate() {
X509Certificate x509Certificate = (X509Certificate) x509obj;
return x509Certificate;
}
public BigInteger getPubModulus() {
JCERSAPublicKey pubKey = (JCERSAPublicKey) x509obj.getPublicKey();
BigInteger pubMod = pubKey.getModulus();
return pubMod;
}
public int getPubModulusSize() {
JCERSAPublicKey pubKey = (JCERSAPublicKey) x509obj.getPublicKey();
BigInteger pubMod = pubKey.getModulus();
return pubMod.bitLength();
}
public BigInteger getSerial() {
BigInteger serial = x509obj.getSerialNumber();
return serial;
}
public String getSubjKeyId() {
SubjectKeyIdentifierStructure subjKIS;
byte[] keyIdBytes;
try {
subjKIS = getSubjectKeyIdentifierStructure();
} catch (X509ReaderNoSuchExtensionException ex) {
return null;
} catch (X509ReaderDecodeException ex) {
return null;
}
keyIdBytes = subjKIS.getKeyIdentifier();
String out = StaticHelpers.bytes2hex(keyIdBytes);
return out;
}
public BigInteger getAuthKeyIdSerial() {
BigInteger serial = BigInteger.ZERO;
AuthorityKeyIdentifierStructure authKIS = getAKISNoExcept();
if (authKIS == null) {
return null;
}
serial = authKIS.getAuthorityCertSerialNumber();
return serial;
}
public String getAuthKeyIdDirname() {
String dirName = null;
AuthorityKeyIdentifierStructure authKIS = getAKISNoExcept();
if (authKIS == null) {
return null;
}
GeneralNames genNames = authKIS.getAuthorityCertIssuer();
if (genNames == null) {
return null;
}
GeneralName[] nameObjs = genNames.getNames();
for (int i = 0; i < nameObjs.length; i++) {
if (nameObjs[i].getTagNo() == 4) {
X509Name name = (X509Name) nameObjs[i].getName();
dirName = name.toString();
break;
}
}
return dirName;
}
public String getAuthKeyId() {
AuthorityKeyIdentifierStructure authKIS = getAKISNoExcept();
if (authKIS == null) {
return null;
}
byte[] authIdBytes;
authIdBytes = authKIS.getKeyIdentifier();
if (authIdBytes == null) {
return null;
}
String out = StaticHelpers.bytes2hex(authIdBytes);
return out;
}
private AuthorityKeyIdentifierStructure getAKISNoExcept() {
AuthorityKeyIdentifierStructure authKIS;
try {
authKIS = getAuthorityKeyIdentifierStructure();
} catch (X509ReaderNoSuchExtensionException ex) {
return null;
} catch (X509ReaderDecodeException ex) {
return null;
}
return authKIS;
}
private SubjectKeyIdentifierStructure getSubjectKeyIdentifierStructure() throws X509ReaderNoSuchExtensionException, X509ReaderDecodeException {
byte[] subjKeyIdBytes = x509obj.getExtensionValue(SubjKeyIdOid);
if (subjKeyIdBytes == null) {
throw new X509ReaderNoSuchExtensionException("SubjectKeyIdentifier");
}
SubjectKeyIdentifierStructure subjKeyId;
try {
subjKeyId = new SubjectKeyIdentifierStructure(subjKeyIdBytes);
} catch (IOException ex) {
throw new X509ReaderDecodeException("Unable to decode SubjectKeyIdentifier extension from Cert", ex);
}
return subjKeyId;
}
public PublicKey getPublicKey() {
PublicKey pubKey = x509obj.getPublicKey();
return pubKey;
}
private AuthorityKeyIdentifierStructure getAuthorityKeyIdentifierStructure() throws X509ReaderNoSuchExtensionException, X509ReaderDecodeException {
byte[] authKeyIdBytes = x509obj.getExtensionValue(AuthKeyIdOid);
if (authKeyIdBytes == null) {
throw new X509ReaderNoSuchExtensionException("AuthorityKeyIdentifier");
}
AuthorityKeyIdentifierStructure authKeyId;
try {
authKeyId = new AuthorityKeyIdentifierStructure(authKeyIdBytes);
} catch (IOException ex) {
throw new X509ReaderDecodeException("Unable to decode AuthorityKeyIdentifier from Cert", ex);
}
return authKeyId;
}
public Calendar getNotBefore() {
Date nb = x509obj.getNotBefore();
if (nb == null) {
return null;
}
return StaticHelpers.dateToCalendar(nb);
}
public Calendar getNotAfter() {
Date na = x509obj.getNotAfter();
if (na == null) {
return null;
}
return StaticHelpers.dateToCalendar(na);
}
public boolean isExpired() {
return isExpired(null);
}
public boolean isPremature() {
return isPremature(null);
}
public boolean isExpired(Date date) {
Date dateObj = (date == null) ? new Date(System.currentTimeMillis()) : date;
return CertUtils.isCertExpired(x509obj, date);
}
public boolean isPremature(Date date) {
Date dateObj = (date == null) ? new Date(System.currentTimeMillis()) : date;
return CertUtils.isCertPremature(x509obj, date);
}
public boolean isDateValid() {
return isDateValid(null);
}
public boolean isDateValid(Date date) {
Date dateObj = (date == null) ? new Date(System.currentTimeMillis()) : date;
return CertUtils.isCertDateValid(x509obj, date);
}
}