سؤال

هل من الممكن إنشاء شهادة X509 في كود Java دون استخدام قلعة نطاط X509V*CertificateGenerator الطبقات؟

هل كانت مفيدة؟

المحلول

القدرة على التوقيع على شهادات ليست جزءًا من مكتبة أو امتداد قياسي Java.

الكثير من الكود المطلوب للقيام بذلك بنفسك هو جزء من النواة. هناك فئات لتشفير وفك تشفير أسماء X.500 ، وملحقات الشهادة X.509 ، والمفاتيح العامة لخوارزميات مختلفة ، وبالطبع ، لأداء التوقيع الرقمي بالفعل.

إن تطبيق هذا بنفسك ليس تافهاً ، لكنه بالتأكيد قابل للتنفيذ - ربما قضيت 4 أو 5 أيام كاملة في المرة الأولى التي قمت فيها بنموذج أولي للعمل لتوقيع الشهادة. كانت جميل تمرين التعلم بالنسبة لي ، ولكن من الصعب تبرير هذه النفقات عندما تكون هناك مكتبات قابلة للاستخدام متاحة مجانًا.

نصائح أخرى

نعم ، ولكن ليس مع الفصول الموثقة للجمهور. لقد وثقت العملية في هذه المقالة.

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

أحببت إجابة VBence ، لكنني ظللت أتلقى الاستثناء التالي:

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

تتوفر جميع المكونات الأساسية لإيجاد شهادة موقعة ذاتيا (التوقيع ، وترميز X509 ، إلخ) في JRE. على عكس BC ، لا تقدم Sun's JCE أي مكالمات عامة للتوقيع على شهادة. ومع ذلك ، جميع الوظائف متوفرة في keytool. يمكنك ببساطة نسخ الكود من KeyTool للقيام بذلك. الطريقة التي تحتاج إلى نسخها هي doSelfCert().

يعتمد على ما تريد بالضبط القيام به (وربما تعريفك لـ "Synely"). كما أشار ZZ Coder ، يمكنك إنشاء شهادة توقيع ذاتيًا مباشرة عن طريق النسخ KeyTool. لكنني لا أعتقد أنه يمكنك إنشاء كائن طلب شهادة PKCS10 مع JCE القياسية ، والتي ربما تحتاج إلى القيام بها إذا كنت ترغب في إنشاء EECs قياسية من CA.

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top