Skip to content
This repository was archived by the owner on Jun 5, 2025. It is now read-only.

Commit b7475fb

Browse files
authored
Merge pull request #4 from Venafi/fix-sans-defaults-etc
Updates to fix issues with SANs, align defaults with industry standards, refine Java code
2 parents 2f9a05e + 970877c commit b7475fb

14 files changed

Lines changed: 330 additions & 156 deletions

File tree

README.md

Lines changed: 99 additions & 66 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,13 @@
1-
# VCert-Java
1+
# VCert Java
22

33
<img src="https://www.venafi.com/sites/default/files/content/body/Light_background_logo.png" width="330px" height="69px"/>
44

55
VCert is a Java library, SDK, designed to simplify key generation and enrollment of machine identities
66
(also known as SSL/TLS certificates and keys) that comply with enterprise security policy by using the
77
[Venafi Platform](https://www.venafi.com/platform/trust-protection-platform) or [Venafi Cloud](https://pki.venafi.com/venafi-cloud/).
88

9-
9+
#### Compatibility
10+
VCert releases are tested using the latest version of Trust Protection Platform. The [latest VCert release](../../releases/latest) should be compatible with Trust Protection Platform 17.3 or higher based on the subset of API methods it consumes.
1011

1112

1213
## Installation
@@ -20,71 +21,103 @@ mvn install
2021

2122
## Usage
2223

23-
A basic example of createing a certificate using the VCert java implementation.
24+
A basic example of creating a certificate using VCert Java:
2425

2526
```
26-
final Config config = Config.builder()
27-
.connectorType(ConnectorType.CLOUD)
28-
.zone("Default")
29-
.build();
30-
31-
final VCertClient client = new VCertClient(config);
32-
final Authentication auth = Authentication.builder()
33-
.apiKey("xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx")
34-
.build();
35-
36-
client.authenticate(auth);
37-
final ZoneConfiguration zoneConfiguration = client.readZoneConfiguration("Public");
38-
39-
40-
41-
// Generate a certificate
42-
CertificateRequest certificateRequest = new CertificateRequest().subject(
43-
new CertificateRequest.PKIXName()
44-
.commonName("opencredo.test")
45-
.organization(Collections.singletonList("Venafi, Inc."))
46-
.organizationalUnit(Arrays.asList("Engineering"))
47-
.country(Collections.singletonList("US"))
48-
.locality(Collections.singletonList("SLC"))
49-
.province(Collections.singletonList("Utah")))
50-
51-
.keyType(KeyType.RSA);
52-
certificateRequest = client.generateRequest(zoneConfiguration, certificateRequest);
53-
54-
55-
// Submit the certificate request
56-
String newCertId = client.requestCertificate(certificateRequest, "Default");
57-
58-
59-
// Retrieve PEM collection from Venafi
60-
final CertificateRequest pickupRequest = new CertificateRequest().pickupId(newCertId);
61-
PEMCollection pemCollection = client.retrieveCertificate(pickupRequest);
62-
System.out.println(pemCollection.certificate());
63-
64-
// Renew the certificate
65-
X509Certificate cert = (X509Certificate) pemCollection.certificate();
66-
String thumbprint = DigestUtils.sha1Hex(cert.getEncoded()).toUpperCase();
67-
final CertificateRequest certificateRequestToRenew = new CertificateRequest().subject(
68-
new CertificateRequest.PKIXName()
69-
.commonName("opencredo.test")
70-
.organization(Collections.singletonList("Venafi, Inc."))
71-
.organizationalUnit(Arrays.asList("Engineering"))
72-
.country(Collections.singletonList("US"))
73-
.locality(Collections.singletonList("SLC"))
74-
.province(Collections.singletonList("Utah")));
75-
76-
client.generateRequest(zoneConfiguration, certificateRequestToRenew);
77-
78-
final RenewalRequest renewalRequest = new RenewalRequest()
79-
.thumbprint(thumbprint)
80-
.request(certificateRequestToRenew);
81-
final String renewedCertificate = client.renewCertificate(renewalRequest);
82-
83-
// Retrieve PEM collection from Venafi
84-
final CertificateRequest renewPickupRequest = new CertificateRequest().pickupId(renewedCertificate);
85-
PEMCollection pemCollectionRenewed = client.retrieveCertificate(pickupRequest);
86-
System.out.println(pemCollectionRenewed.certificate());
87-
27+
final Config config = Config.builder()
28+
.connectorType(ConnectorType.TPP)
29+
.baseUrl("https://tpp.venafi.example/vedsdk")
30+
.build();
31+
32+
/* or for Venafi Cloud
33+
final Config config = Config.builder()
34+
.connectorType(ConnectorType.CLOUD)
35+
.build();
36+
*/
37+
38+
final VCertClient client = new VCertClient(config);
39+
40+
final Authentication auth = Authentication.builder()
41+
.user("local:apiuser")
42+
.password("password")
43+
.build();
44+
45+
/* or for Venafi Cloud
46+
final Authentication auth = Authentication.builder()
47+
.apiKey("aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee")
48+
.build();
49+
*/
50+
51+
client.authenticate(auth);
52+
53+
//////////////////////////////////////
54+
///// Local Generated CSR - RSA //////
55+
//////////////////////////////////////
56+
57+
// Generate a key pair and certificate signing request
58+
CertificateRequest certificateRequest = new CertificateRequest().subject(
59+
new CertificateRequest.PKIXName()
60+
.commonName("vcert-java.venafi.example")
61+
.organization(Collections.singletonList("Example Company"))
62+
.organizationalUnit(Arrays.asList("Example Division"))
63+
.country(Collections.singletonList("US"))
64+
.locality(Collections.singletonList("Salt Lake City"))
65+
.province(Collections.singletonList("Utah")))
66+
.dnsNames(Arrays.asList("alfa.venafi.example", "bravo.venafi.example", "charlie.venafi.example"))
67+
.ipAddresses(Arrays.asList(InetAddress.getByName("10.20.30.40"),InetAddress.getByName("172.16.172.16")))
68+
.emailAddresses(Arrays.asList("larry@venafi.example", "moe@venafi.example", "curly@venafi.example"))
69+
.keyType(KeyType.RSA);
70+
71+
ZoneConfiguration zoneConfiguration = client.readZoneConfiguration("Certificates\\VCert");
72+
certificateRequest = client.generateRequest(zoneConfiguration, certificateRequest);
73+
74+
// Submit the certificate request
75+
client.requestCertificate(certificateRequest, "Certificates\\VCert");
76+
77+
// Retrieve PEM collection from Venafi
78+
PEMCollection pemCollection = client.retrieveCertificate(certificateRequest);
79+
80+
System.out.println(pemCollection.pemPrivateKey());
81+
System.out.println(pemCollection.pemCertificate());
82+
System.out.println(pemCollection.pemCertificateChain());
83+
84+
/////////////////////////////
85+
///// User Provided CSR /////
86+
/////////////////////////////
87+
88+
String csr = "-----BEGIN CERTIFICATE REQUEST-----\n" +
89+
"MIIC8DCCAdgCAQAwgY4xCzAJBgNVBAYTAlVTMQ0wCwYDVQQIEwRVdGFoMRcwFQYD\n" +
90+
"VQQHEw5TYWx0IExha2UgQ2l0eTEYMBYGA1UEChMPRXhhbXBsZSBDb21wYW55MRkw\n" +
91+
"FwYDVQQLExBFeGFtcGxlIERpdmlzaW9uMSIwIAYDVQQDExl2Y2VydC1qYXZhLnZl\n" +
92+
"bmFmaS5leGFtcGxlMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA9PHk\n" +
93+
"bR5i0pV6M08XXi+Z0tAJkIU3TLG0Hr0n5tY6JIcP3Sc8wrodgMN66WUP6oLV/yqR\n" +
94+
"2lKom+dc9dIN9iaVUfnpPwhjyuIMyd0svmU2hnZj3InG5kvqnMnzQvRfWx0OKmMB\n" +
95+
"c652qZsgR3d6I+YufhIsuMxkWMev2njXGZAnThGVMv/iD9dLTO+0lTwwSbvM1lxw\n" +
96+
"YxAwdVFX1+vl0ORyOs4OUqUFv3i6qvS/U/RI45TrgR+XA2/8xPlo5gfGrnFfiyJJ\n" +
97+
"jMctOak2mOVrR/2kXYcOw+37zkpJEADSZBgm/YzqdYtrI8t/M4uClkn9WQgTijC1\n" +
98+
"eN4hFKyTGeOGIqKI/QIDAQABoBwwGgYJKoZIhvcNAQkOMQ0wCzAJBgNVHRMEAjAA\n" +
99+
"MA0GCSqGSIb3DQEBCwUAA4IBAQDOxsP3fFsx/UOLudVm6MAuAFZfZxm7P1sZrYhb\n" +
100+
"tgshSXDlruiO7/ovb8rDrRrKJjAx4+tXlQRsDfxIpvuNcAd7//WCjjIfAoNlGRW4\n" +
101+
"cMtWfvCN1p7XsVer+JJHtM5UZ+oKS06hdPppDP4rfjyhTM5Y0M8JAgMcGsm7lrWU\n" +
102+
"w1ly6k8k5NzadWGOZwvz75qrn0ufHuI96sPsL5wmqty34BfnBy4iMddU3m/Y1qQb\n" +
103+
"VfKV2CRWybwV/QeCtogXvI7Nou2LZQDWI57498Nzif1Zvfy0/ab8XBkX2vMUXcnm\n" +
104+
"1A7/9ezwgYTZvy1rbBSKBSjAx/MAOPUM93OcjT6tKtEeEnI8\n" +
105+
"-----END CERTIFICATE REQUEST-----";
106+
107+
certificateRequest = new CertificateRequest().csr(csr.getBytes())
108+
.csrOrigin(com.venafi.vcert.sdk.certificate.CsrOriginOption.UserProvidedCSR)
109+
.dnsNames(Arrays.asList("alfa.venafi.example", "bravo.venafi.example", "charlie.venafi.example"))
110+
.ipAddresses(Arrays.asList(InetAddress.getByName("10.20.30.40"),InetAddress.getByName("172.16.172.16")))
111+
.emailAddresses(Arrays.asList("larry@venafi.example", "moe@venafi.example", "curly@venafi.example"));
112+
113+
// Submit the certificate request
114+
client.requestCertificate(certificateRequest, "Certificates\\VCert");
115+
116+
// Retrieve PEM collection from Venafi
117+
pemCollection = client.retrieveCertificate(certificateRequest);
118+
119+
System.out.println(pemCollection.pemCertificate());
120+
System.out.println(pemCollection.pemCertificateChain());
88121
89122
```
90123

@@ -132,7 +165,7 @@ mvn "-Dtest=*AT" test
132165
4. Implement and test your changes
133166
5. Commit your changes (`git commit -am 'Added some cool functionality'`)
134167
6. Push to the branch (`git push origin your-branch-name`)
135-
7. Create a new Pull Request (https://github.com/youracct/vcert-java/pull/new/working-branch)
168+
7. Create a new Pull Request (https://github.com/youracct/vcert-java/pull/new/your-branch-name)
136169

137170

138171
## License

src/main/java/com/venafi/vcert/sdk/Config.java

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,10 +9,8 @@
99

1010
import java.io.IOException;
1111
import java.nio.file.Path;
12-
import java.util.Arrays;
1312
import java.util.List;
1413
import java.util.Objects;
15-
import java.util.Set;
1614

1715
import static java.util.Arrays.asList;
1816

src/main/java/com/venafi/vcert/sdk/SignatureAlgorithm.java

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@ public enum SignatureAlgorithm {
66

77
UnknownSignatureAlgorithm(""),
88
MD2withRSA("MD2withRSA"),
9-
109
MD5WithRSA("MD5withRSA"),
1110
SHA1WithRSA("SHA1withRSA"),
1211
SHA256WithRSA("SHA256withRSA"),

src/main/java/com/venafi/vcert/sdk/certificate/CertificateRequest.java

Lines changed: 76 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -5,12 +5,18 @@
55
import com.venafi.vcert.sdk.VCertException;
66
import lombok.Data;
77
import org.bouncycastle.asn1.ASN1ObjectIdentifier;
8-
import org.bouncycastle.asn1.eac.ECDSAPublicKey;
98
import org.bouncycastle.asn1.x500.X500NameBuilder;
109
import org.bouncycastle.asn1.x500.style.BCStyle;
1110
import org.bouncycastle.jce.PKCS10CertificationRequest;
1211
import org.bouncycastle.util.io.pem.PemReader;
13-
import java.util.Base64;
12+
import org.bouncycastle.asn1.x509.GeneralName;
13+
import org.bouncycastle.asn1.x509.GeneralNames;
14+
import org.bouncycastle.asn1.x509.X509Extension;
15+
import org.bouncycastle.asn1.x509.X509Extensions;
16+
import org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers;
17+
import org.bouncycastle.asn1.pkcs.Attribute;
18+
import org.bouncycastle.asn1.DEROctetString;
19+
import org.bouncycastle.asn1.DERSet;
1420

1521
import javax.security.auth.x500.X500Principal;
1622
import java.io.ByteArrayOutputStream;
@@ -20,11 +26,15 @@
2026
import java.security.*;
2127
import java.security.cert.Certificate;
2228
import java.security.interfaces.RSAPublicKey;
29+
import java.security.interfaces.ECPublicKey;
2330
import java.security.spec.ECGenParameterSpec;
2431
import java.time.Duration;
2532
import java.util.Collection;
2633
import java.util.List;
2734
import java.util.Objects;
35+
import java.util.ArrayList;
36+
import java.util.Vector;
37+
import java.util.Base64;
2838

2939
import static java.lang.String.format;
3040
import static java.time.temporal.ChronoUnit.MINUTES;
@@ -72,6 +82,12 @@ public ChainOption chainOption() {
7282
:ChainOption.ChainOptionRootFirst;
7383
}
7484

85+
public PrivateKey privateKey() {
86+
return (!Objects.isNull(keyPair))
87+
?keyPair.getPrivate()
88+
:null;
89+
}
90+
7591
public void generatePrivateKey() throws VCertException {
7692
if(keyPair != null) {
7793
return;
@@ -95,17 +111,40 @@ public void generatePrivateKey() throws VCertException {
95111

96112
public void generateCSR() throws VCertException {
97113
try {
114+
List<GeneralName> sans = new ArrayList<GeneralName>();
115+
116+
for ( String san : dnsNames ) {
117+
sans.add(new GeneralName(GeneralName.dNSName, san));
118+
}
119+
for ( InetAddress san : ipAddresses ) {
120+
sans.add(new GeneralName(GeneralName.iPAddress, new DEROctetString(san.getAddress())));
121+
}
122+
for ( String san : emailAddresses ) {
123+
sans.add(new GeneralName(GeneralName.rfc822Name, san));
124+
}
125+
126+
GeneralNames names = new GeneralNames(sans.toArray(new GeneralName[] {}));
127+
Vector oids = new Vector();
128+
Vector values = new Vector();
129+
130+
oids.add(X509Extensions.SubjectAlternativeName);
131+
values.add(new X509Extension(false, new DEROctetString(names)));
132+
133+
X509Extensions extensions = new X509Extensions(oids, values);
134+
Attribute attribute = new Attribute(PKCSObjectIdentifiers.pkcs_9_at_extensionRequest, new DERSet(extensions));
135+
98136
PKCS10CertificationRequest certificationRequest = new PKCS10CertificationRequest(
99137
signatureAlgorithm.standardName(),
100138
subject.toX500Principal(),
101139
keyPair.getPublic(),
102-
null,
140+
new DERSet(attribute),
103141
keyPair.getPrivate());
104142

105143
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
106144
outputStream.write("-----BEGIN CERTIFICATE REQUEST-----".getBytes());
107145
outputStream.write(System.lineSeparator().getBytes());
108-
outputStream.write(Base64.getEncoder().encode(certificationRequest.getEncoded()));
146+
outputStream.write(Base64.getMimeEncoder().encode(certificationRequest.getEncoded()));
147+
outputStream.write(System.lineSeparator().getBytes());
109148
outputStream.write("-----END CERTIFICATE REQUEST-----".getBytes());
110149
csr = outputStream.toByteArray();
111150
} catch(Exception e) {
@@ -197,8 +236,7 @@ public static class AttributeTypeAndValueSET {
197236
}
198237

199238
public boolean checkCertificate(Certificate certificate) throws VCertException {
200-
// TODO handle enum exception
201-
PublicKeyAlgorithm publicKeyAlgorithm = PublicKeyAlgorithm.valueOf(certificate.getPublicKey().getAlgorithm());
239+
PublicKeyAlgorithm publicKeyAlgorithm = KeyType.from(certificate.getPublicKey().getAlgorithm()).X509Type();
202240

203241
if(keyPair != null && keyPair.getPublic() != null && keyPair.getPrivate() != null) {
204242
if( keyType.X509Type() != publicKeyAlgorithm) {
@@ -214,11 +252,22 @@ public boolean checkCertificate(Certificate certificate) throws VCertException {
214252
}
215253
break;
216254
case ECDSA:
217-
ECDSAPublicKey certEcdsaPublicKey = (ECDSAPublicKey) certificate.getPublicKey();
218-
ECDSAPublicKey reqEcdsaPublicKey = (ECDSAPublicKey) keyPair.getPublic();
219-
// TODO make sure comparison is valid
220-
if(certEcdsaPublicKey.getPrimeModulusP().compareTo(reqEcdsaPublicKey.getPrimeModulusP()) != 0) {
221-
throw new VCertException("unmatched X for eliptic keys");
255+
ECPublicKey certEcPublicKey = (ECPublicKey) certificate.getPublicKey();
256+
ECPublicKey reqEcPublicKey = (ECPublicKey) keyPair.getPublic();
257+
258+
// https://stackoverflow.com/questions/24121801/how-to-verify-if-the-private-key-matches-with-the-certificate
259+
java.security.spec.ECParameterSpec certSpec = certEcPublicKey.getParams(), csrSpec = reqEcPublicKey.getParams();
260+
java.security.spec.EllipticCurve certCurve = certSpec.getCurve(), csrCurve = csrSpec.getCurve();
261+
java.security.spec.ECField certField = certCurve.getField(), csrField = csrCurve.getField();
262+
if ( certSpec != csrSpec //
263+
&& ( certSpec.getCofactor() != csrSpec.getCofactor() //
264+
|| ! certSpec.getOrder().equals( csrSpec.getOrder() ) //
265+
|| ! certSpec.getGenerator().equals( csrSpec.getGenerator() ) //
266+
|| certCurve != csrCurve //
267+
&& ( ! certCurve.getA().equals( csrCurve.getA() ) //
268+
|| ! certCurve.getB().equals( csrCurve.getB() ) //
269+
|| certField.getFieldSize() != csrField.getFieldSize() ) ) ) {
270+
throw new VCertException("unmatched parameters for elliptic keys");
222271
}
223272
break;
224273
default:
@@ -244,11 +293,22 @@ public boolean checkCertificate(Certificate certificate) throws VCertException {
244293
}
245294
break;
246295
case ECDSA:
247-
ECDSAPublicKey certEcdsaPublicKey = (ECDSAPublicKey) certificate.getPublicKey();
248-
ECDSAPublicKey reqEcdsaPublicKey = (ECDSAPublicKey) csr.getPublicKey();
249-
// TODO make sure comparison is valid
250-
if(certEcdsaPublicKey.getPrimeModulusP().compareTo(reqEcdsaPublicKey.getPrimeModulusP()) != 0) {
251-
throw new VCertException("unmatched X for eliptic keys");
296+
ECPublicKey certEcPublicKey = (ECPublicKey) certificate.getPublicKey();
297+
ECPublicKey reqEcPublicKey = (ECPublicKey) csr.getPublicKey();
298+
299+
// https://stackoverflow.com/questions/24121801/how-to-verify-if-the-private-key-matches-with-the-certificate
300+
java.security.spec.ECParameterSpec certSpec = certEcPublicKey.getParams(), csrSpec = reqEcPublicKey.getParams();
301+
java.security.spec.EllipticCurve certCurve = certSpec.getCurve(), csrCurve = csrSpec.getCurve();
302+
java.security.spec.ECField certField = certCurve.getField(), csrField = csrCurve.getField();
303+
if ( certSpec != csrSpec //
304+
&& ( certSpec.getCofactor() != csrSpec.getCofactor() //
305+
|| ! certSpec.getOrder().equals( csrSpec.getOrder() ) //
306+
|| ! certSpec.getGenerator().equals( csrSpec.getGenerator() ) //
307+
|| certCurve != csrCurve //
308+
&& ( ! certCurve.getA().equals( csrCurve.getA() ) //
309+
|| ! certCurve.getB().equals( csrCurve.getB() ) //
310+
|| certField.getFieldSize() != csrField.getFieldSize() ) ) ) {
311+
throw new VCertException("unmatched parameters for elliptic keys");
252312
}
253313
break;
254314
}

0 commit comments

Comments
 (0)