JSSPKIUtility extends ProviderBasedPKIUtility { @Override public X509Certificate createX509Certificate(String dn, Set<X509ExtensionWrapper> extensions, Set<X509ByteExtensionWrapper> byteExtensions, Date startDate, Date endDate, KeyPair clientKeyPair, BigInteger serialNumber, String alternateName) throws IOException { X509CertInfo certInfo = new X509CertInfo(); try { X509Certificate caCert = reader.getCACert(); byte[] publicKeyEncoded = clientKeyPair.getPublic().getEncoded(); certInfo.set(X509CertInfo.ISSUER, new CertificateIssuerName(new X500Name(caCert.getSubjectX500Principal().getEncoded()))); certInfo.set(X509CertInfo.SERIAL_NUMBER, new CertificateSerialNumber(serialNumber)); certInfo.set(X509CertInfo.VALIDITY, new CertificateValidity(startDate, endDate)); certInfo.set(X509CertInfo.SUBJECT, new CertificateSubjectName(new X500Name(dn))); certInfo.set(X509CertInfo.KEY, new CertificateX509Key(X509Key.parse(new DerValue(publicKeyEncoded)))); certInfo.set(X509CertInfo.ALGORITHM_ID, new CertificateAlgorithmId(AlgorithmId.get(SIGNING_ALG_ID))); certInfo.set(X509CertInfo.VERSION, new CertificateVersion(CertificateVersion.V3)); CertificateExtensions certExtensions = buildStandardExtensions(new CertificateExtensions(), dn, clientKeyPair, extensions, caCert, alternateName); certInfo.set(X509CertInfo.EXTENSIONS, certExtensions); if (extensions != null) { for (X509ExtensionWrapper wrapper : extensions) { String value = wrapper.getValue() == null ? "" : wrapper.getValue(); UTF8String der = new UTF8String(value); certExtensions.add(buildCustomExtension(wrapper.getOid(), wrapper.isCritical(), der)); } } if (byteExtensions != null) { for (X509ByteExtensionWrapper wrapper : byteExtensions) { byte[] value = wrapper.getValue() == null ? new byte[0] : wrapper.getValue(); OCTET_STRING der = new OCTET_STRING(value); certExtensions.add(buildCustomExtension(wrapper.getOid(), wrapper.isCritical(), der)); } } X509CertImpl certImpl = new X509CertImpl(certInfo); certImpl.sign(reader.getCaKey(), SIGNING_ALG_ID); CertificateFactory cf = CertificateFactory.getInstance("X.509"); return (X509Certificate) cf.generateCertificate(new ByteArrayInputStream(certImpl.getEncoded())); } catch (GeneralSecurityException e) { throw new RuntimeException("Could not create X.509 certificate", e); } } @Inject  JSSPKIUtility(CertificateReader reader, SubjectKeyIdentifierWriter writer, Configuration config); @Override X509Certificate createX509Certificate(String dn, Set<X509ExtensionWrapper> extensions,
        Set<X509ByteExtensionWrapper> byteExtensions, Date startDate, Date endDate, KeyPair clientKeyPair,
        BigInteger serialNumber, String alternateName); @Override X509CRL createX509CRL(List<X509CRLEntryWrapper> entries, BigInteger crlNumber); static AuthorityKeyIdentifierExtension buildAuthorityKeyIdentifier(RSAPublicKey key); static AuthorityKeyIdentifierExtension buildAuthorityKeyIdentifier(X509Certificate caCert); @Override byte[] getPemEncoded(X509Certificate cert); @Override byte[] getPemEncoded(RSAPrivateKey key); @Override byte[] getPemEncoded(X509CRL crl); @Override void writePemEncoded(X509Certificate cert, OutputStream out); @Override void writePemEncoded(RSAPrivateKey key, OutputStream out); @Override void writePemEncoded(X509CRL crl, OutputStream out); static final byte[] LINE_SEPARATOR; static final String SIGNING_ALG_ID; static final String CRL_PEM_NAME; static final String CERTIFICATE_PEM_NAME; static final String PRIVATE_KEY_PEM_NAME; }
@Test public void testCreateX509Certificate() throws Exception { Date start = new Date(); Date end = Date.from(LocalDate.now().plusDays(365).atStartOfDay(ZoneId.systemDefault()).toInstant()); X509Certificate cert = jssUtil.createX509Certificate("cn=candlepinproject.org", null, null, start, end, subjectKeyPair, BigInteger.valueOf(1999L), "altName"); assertEquals("SHA256withRSA", cert.getSigAlgName()); assertEquals("1999", cert.getSerialNumber().toString()); X509CertificateHolder holder = new X509CertificateHolder(cert.getEncoded()); Extensions bcExtensions = holder.getExtensions(); assertTrue("KeyUsage extension incorrect", KeyUsage.fromExtensions(bcExtensions).hasUsages( KeyUsage.digitalSignature | KeyUsage.keyEncipherment | KeyUsage.dataEncipherment) ); assertTrue("ExtendedKeyUsage extension incorrect", ExtendedKeyUsage.fromExtensions(bcExtensions).hasKeyPurposeId(KeyPurposeId.id_kp_clientAuth) ); assertFalse("Basic constraints incorrectly identify this cert as a CA", BasicConstraints.fromExtensions(bcExtensions).isCA() ); NetscapeCertType expected = new NetscapeCertType( NetscapeCertType.sslClient | NetscapeCertType.smime); NetscapeCertType actual = new NetscapeCertType( (DERBitString) bcExtensions.getExtension(MiscObjectIdentifiers.netscapeCertType).getParsedValue() ); assertArrayEquals( new JcaX509ExtensionUtils().createSubjectKeyIdentifier(subjectKeyPair.getPublic()).getEncoded(), SubjectKeyIdentifier.fromExtensions(bcExtensions).getEncoded() ); CertificateReader reader = injector.getInstance(CertificateReader.class); RSAPrivateCrtKey key = (RSAPrivateCrtKey) reader.getCaKey(); KeyFactory kf = KeyFactory.getInstance("RSA"); RSAPrivateCrtKeySpec ks = kf.getKeySpec(key, RSAPrivateCrtKeySpec.class); RSAPublicKeySpec pubKs = new RSAPublicKeySpec(ks.getModulus(), ks.getPublicExponent()); PublicKey pubKey = kf.generatePublic(pubKs); assertArrayEquals( new JcaX509ExtensionUtils().createAuthorityKeyIdentifier(pubKey).getEncoded(), AuthorityKeyIdentifier.fromExtensions(bcExtensions).getEncoded() ); assertEquals(expected, actual); }
@Test public void testCustomExtensions() throws Exception { Date start = new Date(); Date end = Date.from(LocalDate.now().plusDays(365).atStartOfDay(ZoneId.systemDefault()).toInstant()); String extOid = OIDUtil.REDHAT_OID + "." + OIDUtil.TOPLEVEL_NAMESPACES.get(OIDUtil.ENTITLEMENT_TYPE_KEY); X509ExtensionWrapper typeExtension = new X509ExtensionWrapper(extOid, false, "OrgLevel"); Set<X509ExtensionWrapper> exts = new LinkedHashSet<>(); exts.add(typeExtension); String byteExtOid = OIDUtil.REDHAT_OID + "." + OIDUtil.TOPLEVEL_NAMESPACES.get(OIDUtil.ENTITLEMENT_DATA_KEY); byte[] someBytes = new byte[] { 0xd, 0xe, 0xf, 0xa, 0xc, 0xe, 0xa, 0xc, 0xe }; X509ByteExtensionWrapper byeExtension = new X509ByteExtensionWrapper(byteExtOid, false, someBytes); Set<X509ByteExtensionWrapper> byteExtensions = new LinkedHashSet<>(); byteExtensions.add(byeExtension); X509Certificate cert = jssUtil.createX509Certificate("cn=candlepinproject.org", exts, byteExtensions, start, end, subjectKeyPair, BigInteger.valueOf(2000L), "altName"); ASN1OctetString value = (ASN1OctetString) ASN1OctetString.fromByteArray(cert.getExtensionValue(extOid)); DERUTF8String actual = DERUTF8String.getInstance(value.getOctets()); assertEquals("OrgLevel", actual.getString()); value = (ASN1OctetString) ASN1OctetString.fromByteArray(cert.getExtensionValue(byteExtOid)); ASN1OctetString actualBytes = ASN1OctetString.getInstance(value.getOctets()); assertArrayEquals(someBytes, actualBytes.getOctets()); }