This repository has been archived by the owner on Mar 6, 2024. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 6
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #3 from vmware/certificates
Certificate Support
- Loading branch information
Showing
21 changed files
with
1,151 additions
and
109 deletions.
There are no files selected for viewing
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
294 changes: 294 additions & 0 deletions
294
...ugin-crypto-core/src/main/java/com/vmware/o11n/plugin/crypto/model/CryptoCertificate.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,294 @@ | ||
/* | ||
* Copyright (c) 2017 VMware, Inc. All Rights Reserved. | ||
* SPDX-License-Identifier: BSD-2-Clause | ||
*/ | ||
package com.vmware.o11n.plugin.crypto.model; | ||
|
||
import java.io.IOException; | ||
import java.io.Serializable; | ||
import java.security.NoSuchAlgorithmException; | ||
import java.security.cert.CertificateEncodingException; | ||
import java.security.cert.CertificateException; | ||
import java.security.cert.CertificateParsingException; | ||
import java.security.cert.X509Certificate; | ||
import java.security.spec.InvalidKeySpecException; | ||
import java.util.Date; | ||
import java.util.List; | ||
import java.util.Map; | ||
|
||
import javax.naming.InvalidNameException; | ||
|
||
import org.apache.commons.codec.binary.Base64; | ||
import org.slf4j.Logger; | ||
import org.slf4j.LoggerFactory; | ||
import org.springframework.beans.factory.annotation.Autowired; | ||
|
||
import com.vmware.o11n.plugin.crypto.service.CryptoCertificateService; | ||
import com.vmware.o11n.plugin.sdk.annotation.VsoConstructor; | ||
import com.vmware.o11n.plugin.sdk.annotation.VsoMethod; | ||
import com.vmware.o11n.plugin.sdk.annotation.VsoObject; | ||
import com.vmware.o11n.plugin.sdk.annotation.VsoParam; | ||
import com.vmware.o11n.plugin.sdk.annotation.VsoProperty; | ||
|
||
|
||
@VsoObject( | ||
create=true, | ||
strict=true, | ||
description="A scripting object representing a X.509 certificate") | ||
public class CryptoCertificate implements Serializable, Cloneable { | ||
|
||
@Autowired | ||
private static CryptoCertificateService service; | ||
|
||
private final Logger log = LoggerFactory.getLogger(CryptoCertificate.class); | ||
|
||
/* Constants */ | ||
private static final long serialVersionUID = 7252197349636955057L; | ||
public static final String TYPE = "CryptoCertificate"; | ||
private static final String[] EMPTY_STRING_ARRAY = new String[0]; | ||
|
||
/* Local write once variables: */ | ||
private final X509Certificate cert; | ||
private final String certString; //PEM encoded certificate | ||
|
||
|
||
@VsoConstructor(description="A X.509 Certificate Object") | ||
public CryptoCertificate(@VsoParam(description="PEM encoded certificate") String certString) { | ||
if (service == null) { | ||
service = new CryptoCertificateService(); | ||
} | ||
try { | ||
this.cert = service.parseCertificate(certString); | ||
this.certString = CryptoUtil.pemEncode(this.cert); | ||
} catch (CertificateException ce) { | ||
throw new IllegalArgumentException("Invalid certificate"); | ||
} | ||
} | ||
|
||
public CryptoCertificate(X509Certificate cert) throws CertificateEncodingException { | ||
if (service == null) { | ||
service = new CryptoCertificateService(); | ||
} | ||
this.cert = cert; | ||
this.certString = CryptoUtil.pemEncode(cert); | ||
} | ||
|
||
|
||
|
||
/** | ||
* | ||
* @return | ||
*/ | ||
@VsoProperty(name="encodedBase64", | ||
description="Encoded form of the certificate encoded as a Base64 string. Hashing this can create a fingerprint") | ||
public String getEncodedBase64() { | ||
String toReturn = null; | ||
try { | ||
toReturn = service.getEncodedBase64(this.cert); | ||
} catch (CertificateException ce) { | ||
log.error(ce.getMessage()); | ||
} catch (Throwable e) { | ||
log.error("Unexpected exception: "+e.getMessage()); | ||
} | ||
return toReturn; | ||
} | ||
|
||
/** | ||
* | ||
* @return | ||
*/ | ||
@VsoProperty(name="issuedByDN",description="Distinguished Name the certificate was issued by") | ||
public String getIssuedByDN() { | ||
return this.cert.getIssuerDN().getName(); | ||
} | ||
|
||
/** | ||
* | ||
* @return | ||
* @throws InvalidNameException | ||
*/ | ||
@VsoProperty(name="issuedByMap",description="issuedByDN parsed into key/value pairs") | ||
public Map<String,String> getIssuedByMap() throws InvalidNameException { | ||
return service.parseDN(this.getIssuedByDN()); | ||
} | ||
|
||
/** | ||
* | ||
* @return | ||
*/ | ||
@VsoProperty(name="issuedToDN",description="Distinguished Name the certificate was issued to") | ||
public String getIssuedToDN() { | ||
return this.cert.getSubjectDN().getName(); | ||
} | ||
|
||
/** | ||
* | ||
* @return | ||
* @throws InvalidNameException | ||
*/ | ||
@VsoProperty(name="issuedToMap",description="issuedToDN parsed into key/value pairs") | ||
public Map<String,String> getIssuedToMap() throws InvalidNameException { | ||
return service.parseDN(this.getIssuedToDN()); | ||
} | ||
|
||
|
||
/** | ||
* | ||
* @return | ||
*/ | ||
@VsoProperty(name="pemEncoded", | ||
description="PEM Encoding of the certificate") | ||
public String getPemEncoded() { | ||
return this.certString; | ||
} | ||
|
||
/** | ||
* | ||
* @return | ||
*/ | ||
@VsoProperty(name="publicKeyPem", | ||
description="The RSA Public Key in PEM format found in the certificate") | ||
public String getPublicKeyPem() { | ||
return service.getPublicKeyPem(this.cert); | ||
} | ||
|
||
/** | ||
* | ||
* @return | ||
*/ | ||
@VsoProperty(name="serialNumber",description="Serial Number of the Certificate") | ||
public String getSerialNumber() { | ||
return service.getSerialNumber(this.cert); | ||
} | ||
|
||
/** | ||
* | ||
* @return | ||
*/ | ||
@VsoProperty(name="sha1Fingerprint", | ||
description="SHA1 fingerprint of the certificate") | ||
public String getSha1Fingerprint() { | ||
String toReturn = null; | ||
try { | ||
toReturn = service.getSha1Fingerprint(this.cert); | ||
} catch (CertificateException ce) { | ||
log.error(ce.getMessage()); | ||
} catch (Throwable e) { | ||
log.error("Unexpected exception: "+e.getMessage()); | ||
} | ||
return toReturn; | ||
} | ||
|
||
/** | ||
* | ||
* @return | ||
*/ | ||
@VsoProperty(name="sha256Fingerprint", | ||
description="SHA256 fingerprint of the certificate") | ||
public String getSha256Fingerprint() { | ||
String toReturn = null; | ||
try { | ||
toReturn = service.getSha256Fingerprint(this.cert); | ||
} catch (CertificateException ce) { | ||
log.error(ce.getMessage()); | ||
} catch (Throwable e) { | ||
log.error("Unexpected exception: "+e.getMessage()); | ||
} | ||
return toReturn; | ||
} | ||
|
||
/** | ||
* | ||
* @return | ||
*/ | ||
@VsoProperty(name="signatureAlgorithm",description="Signature algorithm used by the certificate signer") | ||
public String getSignatureAlgorithm() { | ||
return this.cert.getSigAlgName(); | ||
} | ||
|
||
/** | ||
* | ||
* | ||
* @return | ||
*/ | ||
@VsoProperty(name="signatureBase64",description="Base64 encoded signature of the certificate") | ||
public String getSignatureBase64 () { | ||
byte[] sig = this.cert.getSignature(); | ||
return Base64.encodeBase64String(sig); | ||
} | ||
|
||
|
||
/** | ||
* | ||
* @return | ||
*/ | ||
@VsoProperty(name="subjectAlternativeNames", | ||
description="A list of subject alternative names found in the certificate. Each will have a colon delimited prefix for the type of SAN found. ex: \"dns:\"") | ||
public String[] getSubjectAlternativeNames() { | ||
try { | ||
List<String> san = service.getSubjectAlternativeNames(this.cert); | ||
if (san != null && san.size() > 0) { | ||
return san.toArray(EMPTY_STRING_ARRAY); | ||
} | ||
} catch (CertificateParsingException e) { | ||
log.error(e.toString()); | ||
} | ||
return EMPTY_STRING_ARRAY; | ||
} | ||
|
||
/** | ||
* | ||
* @return | ||
*/ | ||
@VsoMethod(vsoReturnType="Date", | ||
description="The certificate is valid before this date") | ||
public Date getValidBefore() { | ||
return this.cert.getNotAfter(); | ||
} | ||
|
||
/** | ||
* | ||
* @return | ||
*/ | ||
@VsoMethod(vsoReturnType="Date", | ||
description="The certificate is valid after this date") | ||
public Date getValidAfter() { | ||
return this.cert.getNotBefore(); | ||
} | ||
|
||
/** | ||
* | ||
* @param date | ||
* @return | ||
*/ | ||
@VsoMethod(vsoReturnType="boolean", | ||
description="Is the certificate valid based on a provided date") | ||
public boolean isValidOn( @VsoParam(vsoType="Date",description="Date to check certificate validity on") Date date) { | ||
final Date validAfter = this.cert.getNotBefore(); | ||
final Date validBefore = this.cert.getNotAfter(); | ||
|
||
if (validAfter.compareTo(date) > 0) { //'validAfter' is after date | ||
//certificate is not valid yet compared to this date | ||
return false; | ||
} | ||
if (validBefore.compareTo(date) < 0) { // 'validBefore is before date' | ||
//certificate is expired compared to this date | ||
return false; | ||
} | ||
// passing both these checks, the cert is valid for this date | ||
return true; | ||
} | ||
|
||
/** | ||
* | ||
* @param pemKey | ||
* @return | ||
* @throws NoSuchAlgorithmException | ||
* @throws InvalidKeySpecException | ||
* @throws IOException | ||
*/ | ||
@VsoMethod(vsoReturnType="boolean",description="Verifies the Certificate was signed by a signing certificates private key") | ||
public boolean verify( @VsoParam(description="PEM encoded PublicKey of the signing Certificate") String pemKey) throws NoSuchAlgorithmException, InvalidKeySpecException, IOException { | ||
return service.verifyCert(this.cert, pemKey); | ||
} | ||
} |
65 changes: 65 additions & 0 deletions
65
...ypto-core/src/main/java/com/vmware/o11n/plugin/crypto/model/CryptoCertificateManager.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,65 @@ | ||
/* | ||
* Copyright (c) 2017 VMware, Inc. All Rights Reserved. | ||
* SPDX-License-Identifier: BSD-2-Clause | ||
*/ | ||
package com.vmware.o11n.plugin.crypto.model; | ||
|
||
import java.io.IOException; | ||
import java.net.URL; | ||
import java.security.KeyManagementException; | ||
import java.security.NoSuchAlgorithmException; | ||
import java.security.cert.CertificateEncodingException; | ||
import java.security.cert.CertificateException; | ||
import java.security.cert.X509Certificate; | ||
import java.util.ArrayList; | ||
import java.util.List; | ||
|
||
import org.slf4j.Logger; | ||
import org.slf4j.LoggerFactory; | ||
import org.springframework.beans.factory.annotation.Autowired; | ||
|
||
import com.vmware.o11n.plugin.crypto.service.CryptoCertificateService; | ||
import com.vmware.o11n.plugin.sdk.annotation.VsoMethod; | ||
import com.vmware.o11n.plugin.sdk.annotation.VsoObject; | ||
import com.vmware.o11n.plugin.sdk.annotation.VsoParam; | ||
import com.vmware.o11n.plugin.sdk.spring.AbstractSpringPluginFactory; | ||
|
||
import ch.dunes.vso.sdk.api.IPluginFactory; | ||
|
||
@VsoObject( | ||
create=false, | ||
strict=true, | ||
singleton=true, | ||
description="Provides methods to parse or fetch certificates") | ||
public class CryptoCertificateManager { | ||
private final Logger log = LoggerFactory.getLogger(CryptoCertificateManager.class); | ||
|
||
@Autowired | ||
private CryptoCertificateService service; | ||
|
||
public static CryptoCertificateManager createScriptingSingleton(IPluginFactory factory) { | ||
return ((AbstractSpringPluginFactory) factory).createScriptingObject(CryptoCertificateManager.class); | ||
} | ||
|
||
@VsoMethod(description="parses a PEM encoded X.509 Certificate") | ||
public CryptoCertificate parseCertificatePem( | ||
@VsoParam(description="PEM encoded Certificate")String pemCertString) throws CertificateException { | ||
X509Certificate cert = service.parseCertificate(pemCertString); | ||
return new CryptoCertificate(cert); | ||
} | ||
|
||
@VsoMethod(description="Returns array of certificates presented by an https server") | ||
public CryptoCertificate[] getHttpsCertificate( | ||
@VsoParam(description="HTTPS URL to get certificate chain of") String urlString) throws KeyManagementException, NoSuchAlgorithmException, IOException, CertificateEncodingException { | ||
ArrayList<CryptoCertificate> toReturn = new ArrayList<>(); | ||
URL url = new URL(urlString); | ||
List<X509Certificate> certs = service.getCertHttps(url); | ||
if (log.isDebugEnabled() && certs != null){ | ||
log.debug("Number of certs found at url: "+certs.size()); | ||
} | ||
for (X509Certificate cert : certs) { | ||
toReturn.add(new CryptoCertificate(cert)); | ||
} | ||
return toReturn.toArray(new CryptoCertificate[toReturn.size()]); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.