Подтвердить что ты не робот

Создание сертификата X509 на Java без BouncyCastle?

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

4b9b3361

Ответ 1

Возможность подписывать сертификаты не входит в стандартную библиотеку Java или расширение.

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

Реализация этого сама по себе не является тривиальной, но это определенно выполнимо. Я, вероятно, провел 4 или 5 полных дней, когда впервые создал рабочий прототип для подписания сертификата. Это было фантастическое упражнение для меня, но трудно оправдать этот счет, когда бесплатные библиотеки доступны бесплатно.

Ответ 2

Да, но не с общедоступными документами. Я документировал процесс в этой статье.

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 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;
}   

Ответ 3

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 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!");
    }
}

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

java.security.cert.CertificateException: тип класса Subject недействителен.

После того, как многие попытки выяснить, был ли подходящий предметный класс, я узнал, что 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);

Ответ 4

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

Ответ 5

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