Il processo di richiesta del certificato standard (o almeno convenzionale) richiede che la chiave privata corrisponda al publickey per essere certificato. Le operazioni preconfezionate dell'utilità keytool
di Java e della riga di comando openssl
sono limitate a questo processo standard, come lo sono molte altre Q esistenti.
Tuttavia, non è fondamentalmente necessario. Finché si ha una chiave privata per il certificato emittente , nominalmente un'autorità di certificazione e un certificato per quella chiave CA o almeno alcuni metadati critici normalmente incorporati in tale certificato, è possibile emettere un certificato di bambino per un determinato bambino publickey.
Questo può essere fatto con OpenSSL chiamando le routine X509_*
in libcrypto dal codice personalizzato; in Java le classi usate dallo standard keytool
non sono ufficialmente parte delle specifiche JRE ma sono open source, ma se puoi usare le librerie di terze parti BouncyCastle (bcprov + bcpkix) espongono direttamente le funzioni necessarie in un modo conveniente e documentato / forma garantita, quindi lo mostro. Questo crea un certificato molto minimale con poche informazioni e in particolare nessuna delle estensioni comunemente presenti nei certificati reali emessi dalla CA. Se questo non è sufficiente per le tue esigenze, fai una domanda più completa.
Per semplicità leggo il PEM pubkey (soggetto) da un file con nome e la chiave CA e cert da un JKS in un file con nome in un alias denominato. Queste fonti di informazione possono essere sostituite da altre come desideri. Inoltre, non eseguo alcuna gestione degli errori, lasciando Java a fare lo stacktrace predefinito; potresti aver bisogno di meglio.
import java.security.*;
import java.security.cert.X509Certificate;
import java.security.interfaces.RSAPrivateKey;
import java.util.Date;
import org.bouncycastle.asn1.x500.X500Name;
import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo;
import org.bouncycastle.cert.X509v3CertificateBuilder;
import org.bouncycastle.openssl.PEMParser;
import org.bouncycastle.openssl.jcajce.JcaPEMWriter;
import org.bouncycastle.operator.ContentSigner;
import org.bouncycastle.operator.jcajce.JcaContentSignerBuilder;
static void Se179526FakeCert (String[] args) throws Exception {
// pubkey.pem cakey.jks pw alias
Object spki = new PEMParser (new FileReader (args[0])).readObject();
KeyStore ks = KeyStore.getInstance("JKS");
ks.load (new FileInputStream (args[1]), args[2].toCharArray());
PrivateKey cakey = (PrivateKey) ks.getKey (args[3], args[2].toCharArray());
X509Certificate cacert = (X509Certificate) ks.getCertificate (args[3]);
Date now = new Date(), exp = new Date(now.getTime()+30*86400*1000); // 30 days validity
ContentSigner signer = new JcaContentSignerBuilder ("SHA256with"+cakey.getAlgorithm()).build(cakey);
byte[] enc = new X509v3CertificateBuilder(
/*issuer*/new X500Name (cacert.getIssuerX500Principal().getName()), /*serial*/BigInteger.valueOf(now.getTime()),
/*validity*/now, exp, /*subject*/new X500Name ("CN=dummy"), /*spki*/(SubjectPublicKeyInfo) spki
) .build(signer) .getEncoded();
// .addExtension's if&as needed before .build
Certificate cert = CertificateFactory.getInstance ("X.509") .generateCertificate(new ByteArrayInputStream(enc));
// could now store in a keystore; or to write out in PEM:
JcaPEMWriter out = new JcaPEMWriter (new OutputStreamWriter (System.out));
out.writeObject (cert); out.flush();
}