Вопрос по jce, x509certificate, java – Создание сертификата X509 в Java без BouncyCastle?

31

Можно ли разумно создать сертификат X509 в коде Java без использования Bouncy CastleX509V*CertificateGenerator классы?

Ваш Ответ

5   ответов
4

ись, кодирование X509 и т. Д.) Доступны в JRE. В отличие от н.э.с JCE нене предоставлять публичные звонки для подписи сертификата. Тем не менее, все функции доступны в Keytool. Вы можете просто скопировать код из keytool, чтобы сделать это. Метод, который вам нужно скопировать, это.doSelfCert()

К сожалению, Keytool используетsun.* классы для этого. Так что это победилоработать с каждым JRE. Однако вотисходный код Pith
70

мы задокументировали процессв этой статье.

import sun.security.x509.*;
import java.security.cert.*;
import java.security.*;
import java.math.BigInteger;
import java.util.Date;
import java.io.IOException

/** 
 * Create a self-signed X.509 Certificate
 * @param dn the X.509 Distinguished Name, eg "CN=Test, L=London, C=GB"
 * @param pair the KeyPair
 * @param days how many days from now the Certificate is valid for
 * @param algorithm the signing algorithm, eg "SHA1withRSA"
 */ 
X509Certificate generateCertificate(String dn, KeyPair pair, int days, String algorithm)
  throws GeneralSecurityException, IOException
{
  PrivateKey privkey = pair.getPrivate();
  X509CertInfo info = new X509CertInfo();
  Date from = new Date();
  Date to = new Date(from.getTime() + days * 86400000l);
  CertificateValidity interval = new CertificateValidity(from, to);
  BigInteger sn = new BigInteger(64, new SecureRandom());
  X500Name owner = new X500Name(dn);
 
  info.set(X509CertInfo.VALIDITY, interval);
  info.set(X509CertInfo.SERIAL_NUMBER, new CertificateSerialNumber(sn));
  info.set(X509CertInfo.SUBJECT, new CertificateSubjectName(owner));
  info.set(X509CertInfo.ISSUER, new CertificateIssuerName(owner));
  info.set(X509CertInfo.KEY, new CertificateX509Key(pair.getPublic()));
  info.set(X509CertInfo.VERSION, new CertificateVersion(CertificateVersion.V3));
  AlgorithmId algo = new AlgorithmId(AlgorithmId.md5WithRSAEncryption_oid);
  info.set(X509CertInfo.ALGORITHM_ID, new CertificateAlgorithmId(algo));
 
  // Sign the cert to identify the algorithm that's used.
  X509CertImpl cert = new X509CertImpl(info);
  cert.sign(privkey, algorithm);
 
  // Update the algorith, and resign.
  algo = (AlgorithmId)cert.get(X509CertImpl.SIG_ALG);
  info.set(CertificateAlgorithmId.NAME + "." + CertificateAlgorithmId.ALGORITHM, algo);
  cert = new X509CertImpl(info);
  cert.sign(privkey, algorithm);
  return cert;
}   
как вы добавляете расширения? meno
Как этот код устанавливает для BasicConstraint значение true для сертификата с собственной подписью? musterjunk
Есть ли способ сделать это, что не делаетT включает вызов к sun.security.x509. *? Учитывая, что это, на самом деле, не то, что выдолжен использовать. Markus Jevring
Очень хороший совет. Избавил меня от импорта ужасной (и любимой) Bouncycastle lib. Блат Robert Foss
6
import sun.security.x509.*;

import java.security.cert.*;
import java.security.*;
import java.math.BigInteger;
import java.security.cert.Certificate;
import java.util.Date;
import java.io.IOException;

public class Example {
    /**
     * Create a self-signed X.509 Example
     *
     * @param dn        the X.509 Distinguished Name, eg "CN=Test, L=London, C=GB"
     * @param pair      the KeyPair
     * @param days      how many days from now the Example is valid for
     * @param algorithm the signing algorithm, eg "SHA1withRSA"
     */
    public X509Certificate generateCertificate(String dn, KeyPair pair, int days, String algorithm)
            throws GeneralSecurityException, IOException {
        PrivateKey privkey = pair.getPrivate();
        X509CertInfo info = new X509CertInfo();
        Date from = new Date();
        Date to = new Date(from.getTime() + days * 86400000l);
        CertificateValidity interval = new CertificateValidity(from, to);
        BigInteger sn = new BigInteger(64, new SecureRandom());
        X500Name owner = new X500Name(dn);

        info.set(X509CertInfo.VALIDITY, interval);
        info.set(X509CertInfo.SERIAL_NUMBER, new CertificateSerialNumber(sn));
        info.set(X509CertInfo.SUBJECT, owner);
        info.set(X509CertInfo.ISSUER, owner);
        info.set(X509CertInfo.KEY, new CertificateX509Key(pair.getPublic()));
        info.set(X509CertInfo.VERSION, new CertificateVersion(CertificateVersion.V3));
        AlgorithmId algo = new AlgorithmId(AlgorithmId.md5WithRSAEncryption_oid);
        info.set(X509CertInfo.ALGORITHM_ID, new CertificateAlgorithmId(algo));

        // Sign the cert to identify the algorithm that's used.
        X509CertImpl cert = new X509CertImpl(info);
        cert.sign(privkey, algorithm);

        // Update the algorith, and resign.
        algo = (AlgorithmId) cert.get(X509CertImpl.SIG_ALG);
        info.set(CertificateAlgorithmId.NAME + "." + CertificateAlgorithmId.ALGORITHM, algo);
        cert = new X509CertImpl(info);
        cert.sign(privkey, algorithm);
        return cert;
    }

    public static void main (String[] argv) throws Exception {
        KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("RSA");
        KeyPair keyPair = keyPairGenerator.generateKeyPair();
        Example example = new Example();
        String distinguishedName = "CN=Test, L=London, C=GB";
        Certificate certificate = example.generateCertificateOriginal(distinguishedName, keyPair, 365, "SHA256withRSA");
        System.out.println("it worked!");
    }
}

но я продолжал получать следующее исключение:

java.security.cert.CertificateException: недопустимый тип класса субъекта.

После множества попыток выяснитьбыло допустимый предметный класс, который я обнаружил, что X509CerInfo хотел экземпляр X500Name.

1 info.set(X509CertInfo.SERIAL_NUMBER, new CertificateSerialNumber(sn));
2 info.set(X509CertInfo.SUBJECT, new CertificateSubjectName(owner));
3 info.set(X509CertInfo.ISSUER, new CertificateIssuerName(owner));
4 info.set(X509CertInfo.KEY, new CertificateX509Key(pair.getPublic()));

Итак, строки 2 и 3 нужно поменять на

2 info.set(X509CertInfo.SUBJECT, owner);
3 info.set(X509CertInfo.ISSUER, owner);
1

что именно вы хотите сделать (и, вероятно, от вашего определенияздраво»). Как отметил ZZ Coder, вы можете создать самозаверяющий сертификат напрямую, скопировавKeytool, Но я неНе верьте, что вы можете создать объект запроса сертификата PKCS10 со стандартным JCE, что вам, вероятно, потребуется, если вы хотите создать стандартные EEC с подписью CA.

Хм, а почему бы и нет? Keytool может конвертировать самоподписанный в CSR, вам просто нужно скопировать этот код. eckes
16

лиотеки Java или расширения.

Большая часть кода, необходимого для того, чтобы сделать это самостоятельно, является частью ядра. Существуют классы для кодирования и декодирования имен X.500, расширений сертификатов X.509, открытых ключей для различных алгоритмов и, конечно, для фактического выполнения цифровой подписи.

Осуществить это самостоятельно не тривиально, но это определенно выполнимоВероятно, я потратил 4 или 5 полных дней, когда впервые сделал рабочий прототип для подписи сертификата. Это былфантастика упражнение для меня, но этоТрудно оправдать эти расходы, когда есть доступные библиотеки, доступные бесплатно.

@DanielGartmann Это 'не понятно что "код снят Вы говорите о. Твой "нет» ответ предыдущему комментатору? erickson
@DanielGartmann Комментатор спрашивает, верен ли мой ответ в 2017 году. Я думаю, что это так; вы можете'т подписывать сертификаты из коробки, вы должны построить его самостоятельно. Итак, если вы говорите, чтоне так, вы можете объяснить, почему? Но ваш второй комментарий звучит так, как будто вы говорите, что другие ответы неверны в том смысле, как ониЯ применил предоставленные API-интерфейсы (и с этим я согласен). erickson
Нет, фрагмент кода использует устаревшую криптографию (MD5withRSA или SHA1withRSA в Javadoc) для подписи сертификата. Вместо этого я бы рекомендовал использовать SHA256 с RSA, SHA384 с RSA, SHA512 с RSA или SHA256 с ECDSA, SHA384 с ECDSA и SHA512 с ECDSA в зависимости от уровня безопасности, для которого вы разрабатываете. Daniel Gartmann
Это все еще точно с 2017 года? user674669
@erickson да, я, очевидно, отвечаю на user674669 'вопрос Что я имел ввидуфрагмент кода " код, отображаемый в первых 2 ответах ниже (в серой области, содержащей исходный код). Daniel Gartmann

Похожие вопросы