1

我需要在我的證書添加OID 1.3.6.1.5.5.7.1.26的一個新的擴展。添加一個新的擴展我的生成的證書

Certificate Extensions: 10 [1]: ObjectId: 1.3.6.1.5.5.7.1.26 Criticality=false
Extension unknown: DER encoded OCTET string =
0000: 04 0C 30 0A 13 08 33 39 20 64 63 20 32 62 ..0...
39 dc 2b

我想這個OID被認可類似於其他的擴展名如AuthorityInfoAccess

我需要編輯的jar:我在證書,但與下面的錯誤得到這個OID擴展充氣城堡 X509班?

進出口使用ACME4j作爲客戶端和Letsencrypt博爾德作爲我的服務器。

這裏是註冊證書的CSR Builder代碼。

public void sign(KeyPair keypair) throws IOException { 
    //Security.addProvider(new BouncyCastleProvider()); 
    Objects.requireNonNull(keypair, "keypair"); 
    if (namelist.isEmpty()) { 
     throw new IllegalStateException("No domain was set"); 
    } 

    try { 
     GeneralName[] gns = new GeneralName[namelist.size()]; 
     for (int ix = 0; ix < namelist.size(); ix++) { 
      gns[ix] = new GeneralName(GeneralName.dNSName,namelist.get(ix)); 
     } 
     SignatureAlgorithmIdentifierFinder algFinder = new 
       DefaultSignatureAlgorithmIdentifierFinder(); 
     GeneralNames subjectAltName = new GeneralNames(gns); 


     PKCS10CertificationRequestBuilder p10Builder = new  JcaPKCS10CertificationRequestBuilder(namebuilder.build(), keypair.getPublic()); 

     ExtensionsGenerator extensionsGenerator = new ExtensionsGenerator(); 
     extensionsGenerator.addExtension(Extension.subjectAlternativeName,  false, subjectAltName); 
     //extensionsGenerator.addExtension(Extension.authorityInfoAccess,   true, subjectAltName); 
     //extensionsGenerator.addExtension(new ASN1ObjectIdentifier("TBD"),  false, subjectAltName); 
     //extensionsGenerator.addExtension(new  ASN1ObjectIdentifier("1.3.6.1.5.5.7.1.24"), false, subjectAltName); 
     extensionsGenerator.addExtension(new  ASN1ObjectIdentifier("1.3.6.1.5.5.7.1.26").intern(), false, subjectAltName); 
     //extentionsGenerator.addExtension(); 
      p10Builder.addAttribute(PKCSObjectIdentifiers.pkcs_9_at_extensionRequest,  extensionsGenerator.generate()); 


     PrivateKey pk = keypair.getPrivate(); 
     /*JcaContentSignerBuilder csBuilder = new JcaContentSignerBuilder(
         pk instanceof ECKey ? EC_SIGNATURE_ALG :  EC_SIGNATURE_ALG); 
     ContentSigner signer = csBuilder.build(pk);*/ 

     if(pk instanceof ECKey) 
     { 
      AlgorithmIdentifier sigAlg = algFinder.find("SHA1withECDSA"); 
       AlgorithmIdentifier digAlg = new  DefaultDigestAlgorithmIdentifierFinder(). 
        find(sigAlg); 
      ContentSigner signer = new  JcaContentSignerBuilder("SHA256with"+pk.getAlgorithm()).setProvider(BOUNCY_CASTL E_PROVIDER).build(keypair.getPrivate()); 

      csr=p10Builder.build(signer); 
      System.out.println("ZIPED CSR ECDSA: "+csr); 
     } 
     else 
     { 
      ContentSigner signer = new  JcaContentSignerBuilder("SHA256with"+pk.getAlgorithm()).build(keypair.getPrivate ()); 
      csr = p10Builder.build(signer); 
      System.out.println("ZIPED CSR RSA: "+csr); 
     } 

     //csr = p10Builder.build(signer); 
    } catch (Exception ex) { 
     ex.printStackTrace();; 
    } 
} 
+0

請包括您用於生成和驗證證書的代碼以及錯誤的完整堆棧跟蹤。 – pedrofb

+0

請添加您正在使用的工具來解析證書(發生錯誤)。它是'openssl'還是純java與/沒有bouncycastle? – 2017-03-27 11:52:31

+0

我搜索了這個OID並找不到它:http://www.oid-info.com/get/1.3.6.1.5.5.7.1.26(也許這就是爲什麼它是未知的)。 它應該是什麼,一個特定上下文的自定義擴展?在你的代碼中,你正在爲它添加一個'subjectAltName',但**主題備用名**已經有了自己的OID,它不應該被添加到1.3.6.1.5.5.7.1.26。 1.3.6.1.5.5.7.1.26應該有什麼價值? – 2017-03-28 03:01:14

回答

1

注:這些代碼我用bcprov-jdk15on 1.56

你的代碼一些評論。首先,請注意ASN1結構:

TNAuthorizationList ::= SEQUENCE SIZE (1..MAX) OF TNEntry 

TNEntry ::= CHOICE { 
    spc [0] ServiceProviderCodeList, 
    range [1] TelephoneNumberRange, 
    one  E164Number 
} 

注意TNEntry選擇,並TNAuthorizationListTNEntry對象序列。所以your class name應改爲TNEntry。在下面的代碼中,請記住我已將課程名稱更改爲TNEntry

我也改變了這堂課的一些東西。在getInstance(Object obj)方法,類型SPC範圍領域是不正確的(根據ASN1定義,它們都是序列):

switch (tag) { 
    case spc: 
    case range: // both are sequences 
     return new TNEntry(tag, ASN1Sequence.getInstance(tagObj, false)); 
    // not sure about "one" field, as it's not tagged 
} 

我只是不知道如何處理一個字段,因爲它沒有被標記。也許它應該是​​,或者可能有另一種類型的「無標記」選擇。

在這同一類(記住,我已經更名爲TNEntry),我也去掉了構造public TNEntry(int tag, String name),因爲我不知道它是否適用(至少我並不需要使用它,但你可以留着它,如果你想),我已經改變了toString方法返回一個更可讀的字符串:

​​3210

而且我還創建了一個TNAuthorizationList類,它持有序列TNEntry對象(記得我已將您的課程名稱更改爲TNEntry,因此此TNAuthorizationList課程是一個不同的)。請注意,我還創建了一個常量保持OID(只是爲了讓事情變得稍微容易一些):

public class TNAuthorizationList extends ASN1Object { 
    // put OID in a constant, so I don't have to remember it all the time 
    public static final ASN1ObjectIdentifier TN_AUTH_LIST_OID = new ASN1ObjectIdentifier("1.3.6.1.5.5.7.1.26"); 

    private TNEntry[] entries; 

    public TNAuthorizationList(TNEntry[] entries) { 
     this.entries = entries; 
    } 

    public static TNAuthorizationList getInstance(Object obj) { 
     if (obj instanceof TNAuthorizationList) { 
      return (TNAuthorizationList) obj; 
     } 
     if (obj != null) { 
      return new TNAuthorizationList(ASN1Sequence.getInstance(obj)); 
     } 

     return null; 
    } 

    public static TNAuthorizationList getInstance(ASN1TaggedObject obj, boolean explicit) { 
     return getInstance(ASN1Sequence.getInstance(obj, explicit)); 
    } 

    private TNAuthorizationList(ASN1Sequence seq) { 
     this.entries = new TNEntry[seq.size()]; 

     for (int i = 0; i != seq.size(); i++) { 
      entries[i] = TNEntry.getInstance(seq.getObjectAt(i)); 
     } 
    } 

    public TNEntry[] getEntries() { 
     TNEntry[] tmp = new TNEntry[entries.length]; 
     System.arraycopy(entries, 0, tmp, 0, entries.length); 
     return tmp; 
    } 

    @Override 
    public ASN1Primitive toASN1Primitive() { 
     return new DERSequence(entries); 
    } 

    public String toString() { 
     String sep = System.getProperty("line.separator"); 
     StringBuffer buf = new StringBuffer(); 

     buf.append(this.getClass().getSimpleName()); 
     buf.append(":").append(sep); 
     for (TNEntry tnEntry : entries) { 
      buf.append(" "); 
      buf.append(tnEntry.toString()); 
      buf.append(sep); 
     } 
     return buf.toString(); 
    } 
} 

現在,添加此擴展的證書,我做了這個代碼(有一些樣本數據,因爲我不知道應該是什麼在各個領域中的現實世界的情況):

X509v3CertificateBuilder builder = new JcaX509v3CertificateBuilder(etc...); 

// create TNEntries for TNAuthorizationList 
TNEntry[] entries = new TNEntry[2]; 

// create a "spc" entry 
DERIA5String[] cList = new DERIA5String[] { new DERIA5String("spc1"), new DERIA5String("spc2") }; 
DERSequence spc = new DERSequence(cList); 
entries[0] = TNEntry.getInstance(new DERTaggedObject(false, TNEntry.spc, spc)); 

// create a "range" entry 
DERSequence range = new DERSequence(new ASN1Encodable[] { new DERIA5String("123456"), new ASN1Integer(1) }); 
entries[1] = TNEntry.getInstance(new DERTaggedObject(false, TNEntry.range, range)); 

TNAuthorizationList tnAuthList = new TNAuthorizationList(entries); 
builder.addExtension(TNAuthorizationList.TN_AUTH_LIST_OID, false, tnAuthList); 

一旦你的證書對象(在我的例子一個X509Certificate),你可以這樣做:

// cert is a X509Certificate instance 
ASN1Primitive value = X509ExtensionUtil.fromExtensionValue(cert.getExtensionValue(TNAuthorizationList.TN_AUTH_LIST_OID.getId())); 
TNAuthorizationList authList = TNAuthorizationList.getInstance(value); 
System.out.println(authList.toString()); 

輸出將是:

TNAuthorizationList: 
    TNEntry [0]: ServiceProviderCodeList: 
    spc1 
    spc2 

    TNEntry [1]: TelephoneNumberRange: 
    start: 123456 
    count: 1 

注:

  • 正如我所說的,這個代碼是不完整的,因爲我不知道如何處理的一個TNEntry,因爲它沒有被標記(我不知道它是否必須是​​,或者是否有另一種類型的對象用於「無標記」字段)。
  • 你也可以做一些改進:
    • ServiceProviderCodeList可以有1〜3個元素,所以你可以驗證它的大小
    • TelephoneNumberRange:在開始領域有特定的格式(FROM ("#*")我認爲它的意思只有這些字符被接受),因此您也可以驗證它
    • 要創建ServiceProviderCodeListTelephoneNumberRange的值,我手動創建了DERSequence對象,但是您可以爲它們創建自定義類:ServiceProviderCodeList可容納的​​列表,並在其構造(尺寸爲1至3)進行適當的驗證,並TelephoneNumberRange可能有開始計數字段(開始值的適當的驗證) - 和toASN1Primitive只需要按照正確的順序

返回其字段的DERSequence爲您parsing issues,我已經檢查acme4j code,它採用的是java.security.cert.X509Certificate類。此類的toString()方法(使用Sun的默認提供程序時)會生成此「擴展未知」輸出(根據相應的code)。

因此,爲了正確地解析它(顯示爲上述格式的輸出),您可能需要更改acme4j的代碼(或寫你自己的),創建一個新的toString()方法,包括在新TNAuthorizationList類這種方法。

當您提供顯示您如何使用acme4j的代碼時,如果需要,我會相應更新此答案。

+1

你是天才雨果。我只是想用你的語言謝謝你, ** Muito obrigado **:D。我在證書中獲得了擴展名。但它適用於自簽名證書的權利。不適用於Lets加密CA簽名證書。我希望服務器會忽略這個擴展!和Im仍然得到'的ObjectId:1.3.6.1.5.5.7.1.26臨界=假 **擴展未知:DER編碼OCTET字符串= ** 0000:04 25 30 23 A0 14 16 08 33 39 20 61 62 20 32 36。%0#....39 ab 26 0010:16 08 32 31 20 63 36 20 30 31 A1 0B 16 06 31 32 .21 c3 456'爲什麼它不承認這個擴展? –

+0

不客氣。你會得到「擴展名未知」,因爲解析證書的系統沒有使用你的新類。獲得可讀輸出的唯一方法是使用這些類(嘗試查找此代碼並進行更改,當然,如果您有權訪問它) – 2017-03-30 09:51:58

+0

Hugo,如何以及在何處添加我的類。我可以找到解析我的證書的地方。這是用CertificateFactory還是JcaX509v3CertificateBuilder完成的?我使用acme4j作爲客戶端。這裏是該客戶端環境的鏈接https://github.com/shred/acme4j –

1

由於OID 1.3.6.1.5.5.7.1.26仍然是一個草案,我相信這是不太可能的工具和系統,如:讓我們加密認識到這一點擴展(他們可能會做之後這個擴展變成了官方,我真的不知道這種批准背後的官僚過程)。

這意味着你可能不得不代碼它。我一直在使用Bouncy Castle幾年,但從來沒有創建一個新的ASN1結構。但是如果必須的話,我會先看看它的源代碼作爲初步指導。

考慮到該擴展名的ASN1結構:

TNAuthorizationList ::= SEQUENCE SIZE (1..MAX) OF TNEntry 

TNEntry ::= CHOICE { 
    spc [0] ServiceProviderCodeList, 
    range [1] TelephoneNumberRange, 
    one  E164Number 
    } 

ServiceProviderCodeList ::= SEQUENCE SIZE (1..3) OF IA5String 

-- Service Provider Codes may be OCNs, various SPIDs, or other 
-- SP identifiers from the telephone network 

TelephoneNumberRange ::= SEQUENCE { 
    start E164Number, 
    count INTEGER 
    } 

E164Number ::= IA5String (SIZE (1..15)) (FROM ("#*")) 

擴展值必須是TNEntrySEQUENCE。所以,你可以使用ASN1Sequence(或它的子類DERSequence)和放TNEntry實例裏面。

要創建一個TNEntry,您需要實現ASN1Choice(請參閱GeneralName類的源代碼並執行類似操作)。

依此類推,直到你有整個結構映射到它們各自的類別,使用充氣城堡內置類來支持你(有​​爲IA5StringDERIntegerINTEGER,可在ServiceProviderCodeList和使用TelephoneNumberRange

之後,你可以建立自己的分析器,它可以識別這個擴展。但正如我所說的,別指望其他工具能夠識別它。

+1

非常感謝雨果。對不起,我沒有15個聲望投票您的評論!我爲這個OID創建了一個新的ASN1結構。我將發佈下面的代碼。我對它幾乎沒有懷疑。其他擴展名,例如'GeneralName',如您所提到的,在其他類中被引用,如** PKIHeaderBuilder **,** X509CertificateObject **,** X509ExtentionUtil **等。我是否需要像在其他類似的類中一樣添加這個新的擴展?你已經提到了構建你自己的解析器,請你簡單指定它。 –

+0

我不認爲你需要。我只是建議看一下'GeneralName'來知道如何用Bouncy Castle類實現一個自定義的ASN1結構。由於'TNAuthorizationList'仍然是一個草稿,你不需要在任何地方添加它。我會做的是隻此擴展處理它需要的地方(例如,分析其價值,增添了證書,和任何使用情況下,你可能有) – 2017-03-28 16:12:56

+0

通過「建立你自己的解析器,」我的意思是一樣的OpenSSL以及類似的工具贏得不認識這個擴展名(他們不會像其他名字那樣顯示它的名字 - 比如** Keyusage **,** Subject Alternative Names **等等)。因此,如果您想以可讀的方式顯示此擴展名的名稱(** TNAuthorizationList **)及其所有字段(spc,range ...),則必須編寫自定義分析器來完成此操作(但那會更容易,因爲你已經創建了ASN1結構) – 2017-03-28 16:22:04

1

眼下,用於測試目的,我只是路過從我的CA博爾德的字符串值。所以要了解它,這是TNAUthList的自定義ASN1對象結構。

public class TNAuthorizationList extends ASN1Object implements ASN1Choice{ 

public static final int spc      = 0; 
public static final int range     = 1; 

private ASN1Encodable obj; 
private int   tag; 

public TNAuthorizationList(
     int   tag, 
     ASN1Encodable name) 
    { 
     this.obj = name; 
     this.tag = tag; 
    } 

public TNAuthorizationList(
     int  tag, 
     String name) 
    { 
     this.tag = tag; 

     if (tag == spc) 
     { 
      this.obj = new DERIA5String(name); 
     } 
     else if (tag == range) 
     { 
      this.obj = new ASN1ObjectIdentifier(name); 
     } 
     else 
     { 
      throw new IllegalArgumentException("can't process String for tag: " + tag); 
     } 
    } 

public static TNAuthorizationList getInstance(
     Object obj) 
    { 
     if (obj == null || obj instanceof TNAuthorizationList) 
     { 
      return (TNAuthorizationList)obj; 
     } 

     if (obj instanceof ASN1TaggedObject) 
     { 
      ASN1TaggedObject tagObj = (ASN1TaggedObject)obj; 
      int     tag = tagObj.getTagNo(); 

      switch (tag) 
      { 
      case spc: 
       return new TNAuthorizationList(tag, DERIA5String.getInstance(tagObj, false)); 
      } 
     } 

     if (obj instanceof byte[]) 
     { 
      try 
      { 
       return getInstance(ASN1Primitive.fromByteArray((byte[])obj)); 
      } 
      catch (IOException e) 
      { 
       throw new IllegalArgumentException("unable to parse encoded general name"); 
      } 
     } 

     throw new IllegalArgumentException("unknown object in getInstance: " + obj.getClass().getName()); 
    } 

public static TNAuthorizationList getInstance(
     ASN1TaggedObject tagObj, 
     boolean   explicit) 
    { 
     return TNAuthorizationList.getInstance(ASN1TaggedObject.getInstance(tagObj, true)); 
    } 

    public int getTagNo() 
    { 
     return tag; 
    } 

    public ASN1Encodable getSpc() 
    { 
     return obj; 
    } 

    public String toString() 
    { 
     StringBuffer buf = new StringBuffer(); 

     buf.append(tag); 
     buf.append(": "); 
     switch (tag) 
     { 
     case spc: 
      buf.append(DERIA5String.getInstance(obj).getString()); 
      break; 
     default: 
      buf.append(obj.toString()); 
     } 
     return buf.toString(); 
    } 



/** 
*TNEntry ::= CHOICE { 
*  spc [0] ServiceProviderCodeList, 
*  range [1] TelephoneNumberRange, 
*  one  E164Number 
*  } 
*/ 
@Override 
public ASN1Primitive toASN1Primitive() { 
    // TODO Auto-generated method stub 
    return new DERTaggedObject(false, tag, obj); 
} 

}

如你所說我已經通過了OID值X509Util類,並打印輸出。

ASN1Object o = X509ExtensionUtil.fromExtensionValue(cert.getExtensionValue("1.3.6.1.5.5.7.1.26")); 
    System.out.println("ASN1 Object: "+o); 
    System.out.println("get Class "+o.getClass()); 

和O/P是

ASN1 Object: [SPID : 39 dc 2b] 
get Class class org.bouncycastle.asn1.DLSequence 

這是罰款。我如何解析這與我的自定義ASN1結構?

0

這是如何使用ACME4j。

public class RSASignedCertificate { 

private static final int KEY_SIZE = 2048; 

private static final Logger LOG = Logger.getLogger(CCIDClient.class); 

@SuppressWarnings("unused") 
public void fetchCertificate(String domain,String spid, String email, int port, 
     String username, String password, String certPath) throws Exception { 
    // Load or create a key pair for the user's account 
    boolean createdNewKeyPair = true; 
    KeyPair domainKeyPair = null; 

    DomainKeyStore details = null; 
    KeyPair userKeyPair = null; 

    userKeyPair = KeyPairUtils.createKeyPair(KEY_SIZE); 

    DateFormat dateTime = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss"); 
    Date date; 
    details = new DomainKeyStore(); 

    // Create Hibernate Util class Object 

    // dao=new HibernateDAO(); 
    boolean isDomainExist = new HibernateDAO().isDomainExist(domain); 
    if (isDomainExist) { 

     details.setDomain(domain); 
     details.setEmail(email); 
     date = new Date(); 
     details.setUpdatedOn(dateTime.parse(dateTime.format(date))); 
     boolean updateresult = new HibernateDAO().updateDetails(details); 

     LOG.info("User Details Updated "); 
    } 

    else { 

     date = new Date(); 
     // Date currentDateTime = dateTime.parse(dateTime.format(date)); 
     details.setEmail(email); 
     details.setDomain(domain); 
     details.setStatus("Not Registered"); 
     details.setCreatedOn(dateTime.parse(dateTime.format(date))); 
     details.setUpdatedOn(dateTime.parse(dateTime.format(date))); 

     boolean isInserted = new HibernateDAO().insertDetails(details); 
     if (!isInserted) { 
      throw new AcmeException("Unable to insert details"); 
     } 
     LOG.info("User Details inserted "); 
    } 
    // details=dao.getDetails(domain); 

    Session session = null; 
    if (userKeyPair != null) { 
     session = new Session("http://192.168.1.143:4000/directory", userKeyPair); 
     System.out.println(session.getServerUri().toString()); 
     System.out.println(session.resourceUri(Resource.NEW_REG)); 
    } 
    Registration reg = null; 
    try { 
     reg = new RegistrationBuilder().create(session); 
     LOG.info("Registered a new user, URI: " + reg.getLocation()); 
    } catch (AcmeConflictException ex) { 
     reg = Registration.bind(session, ex.getLocation()); 
     LOG.info("Account does already exist, URI: " + reg.getLocation()); 
    } 
    date = new Date(); 
    details.setStatus("Registered"); 
    details.setRegistrationDate(dateTime.parse(dateTime.format(date))); 
    details.setUpdatedOn(dateTime.parse(dateTime.format(date))); 

    new HibernateDAO().updateRegistration(details); 

    URI agreement = reg.getAgreement(); 
    LOG.info("Terms of Service: " + agreement); 

    if (createdNewKeyPair) { 
     boolean accepted = acceptAgreement(reg, agreement); 
     if (!accepted) { 
      return; 
     } 
    } 

    Authorization auth = null; 
    try { 
     auth = reg.authorizeDomain(spid); 
    } catch (AcmeUnauthorizedException ex) { 
     // Maybe there are new T&C to accept? 
     boolean accepted = acceptAgreement(reg, agreement); 
     if (!accepted) { 
      return; 
     } 
     // Then try again... 
     auth = reg.authorizeDomain(spid); 
    } 
    LOG.info("New authorization for domain " + spid); 
    LOG.info("Authorization " + auth); 

    Challenge challenge = tokenChallenge(auth); 
    // System.out.println("Challendg status before trigger :"+challenge.getStatus()); 
    if (challenge == null) { 
     throw new AcmeException("No Challenge found"); 
    } 

    if (challenge.getStatus() == Status.VALID) { 
     return; 
    } 
    challenge.trigger(); 
    int attempts = 1; 
    // System.out.println("Challendg status after trigger :"+challenge.getStatus()); 
    while (challenge.getStatus() != Status.VALID && attempts-- > 0) { 
     // System.out.println(challenge.getStatus()); 
     if (challenge.getStatus().equals(Status.PENDING)) { 
      challenge.update(); 
      try { 
       Thread.sleep(100); 
      } catch (InterruptedException e) { 
       LOG.warn("interrupted", e); 
       e.printStackTrace(); 
      } 
     } 
     if (challenge.getStatus() == Status.INVALID) { 
      LOG.error("Challenge failed... Giving up."); 
      throw new AcmeServerException("Challenge Failed"); 
     } 
     try { 
      Thread.sleep(3000L); 
     } catch (InterruptedException ex) { 
      LOG.warn("interrupted", ex); 
     } 
     challenge.update(); 
    } 
    if (challenge.getStatus() != Status.VALID) { 
     LOG.error("Failed to pass the challenge... Giving up."); 
     throw new AcmeServerException("Challenge Failed"); 
    } 

    date = new Date(); 
    details.setStatus("Clallenge Completed"); 
    details.setUpdatedOn(dateTime.parse(dateTime.format(date))); 
    new HibernateDAO().updateChallenge(details); 

    domainKeyPair = KeyPairUtils.createKeyPair(KEY_SIZE); 

    // Generate a CSR for the domain 
    CSRBuilder csrb = new CSRBuilder(); 
    csrb.addDomains(spid); 
    csrb.sign(domainKeyPair); 

    // System.out.println("CSR:" +csrb.getCSR()); 

    LOG.info("Keys Algoritham: " 
      + domainKeyPair.getPrivate().getAlgorithm()); 

    PrivateKeyStore privatekey = new PrivateKeyStore(); 
    privatekey.setDomain(spid); 
    privatekey.setEmail(email); 
    privatekey.setPrivateKey(domainKeyPair.getPrivate().getEncoded()); 

    PublicKeyStore publickey = new PublicKeyStore(); 
    publickey.setDomain(spid); 
    publickey.setEmail(email); 
    publickey.setPublicKey(domainKeyPair.getPublic().getEncoded()); 

     // Request a signed certificate 
    Certificate certificate = reg.requestCertificate(csrb.getEncoded()); 
    LOG.info("Success! The certificate for spids " + spid 
      + " has been generated!"); 
    LOG.info("Certificate URI: " + certificate.getLocation()); 

    String nameFile = spid.replace(".", "") + ".cer"; 

    X509Certificate sscert = CertificateUtils.createTlsSniCertificate(domainKeyPair,spid); 

    System.out.println("Certificate :" +sscert); 

    ASN1Primitive o = X509ExtensionUtil.fromExtensionValue(sscert.getExtensionValue(TNAuthorizationList.TN_AUTH_LIST_OID.getId())); 
    System.out.println("ASN1:Object "+o+" class: "+o.getClass()); 
    TNAuthorizationList TNList = TNAuthorizationList.getInstance(o); 
    System.out.println(TNList.toString()); 

    File createFile = new File(certPath + nameFile); 
    if (!createFile.exists()) { 
     createFile.createNewFile(); 
    } 

    try (FileWriter fw = new FileWriter(createFile.getAbsoluteFile())) { 
     CertificateUtils.writeX509Certificate(sscert, fw); 
     System.out.println("Certificate " + sscert); 
     System.out.println("Certificate Content" + fw); 
    } 

    date = new Date(); 
    Calendar c = Calendar.getInstance(); 
    c.setTime(new Date()); 
    c.add(Calendar.DATE, 90); 
    details.setIssueDate(dateTime.parse(dateTime.format(date))); 
    details.setUpdatedOn(dateTime.parse(dateTime.format(date))); 
    details.setValidUntil(dateTime.parse(dateTime.format(c.getTime()))); 
    details.setStatus("Issued"); 



    details.setCertPath(certPath + nameFile); 
    new HibernateDAO().updateCertificate(details); 

} 

public boolean acceptAgreement(Registration reg, URI agreement) throws AcmeException 
     { 

    reg.modify().setAgreement(agreement).commit(); 
    LOG.info("Updated user's ToS"); 

    return true; 
} 

public Challenge tokenChallenge(Authorization auth) 
{ 
    TokenChallenge chall = auth.findChallenge(TokenChallenge.TYPE); 

    LOG.info("File name: " + chall.getType()); 
    //LOG.info("Content: " + chall.`); 
    return chall; 

} 
+0

我想打印「extension unknown」的行是這樣的:'System.out.println(「Certificate」+ sscert);'對嗎?可能'CertificateUtils.createTlsSniCertificate()'使用SUN默認的提供程序創建它。然後,'System.out.println'調用證書的'toString'方法,並且此方法不能識別擴展。如果我是對的,那麼你需要用一個自定義的代碼(使用你的類)來替換這個代碼來得到格式化的輸出(就像你在'System.out.println(TNList.toString())''中做的那樣)。我不知道最好的方法,也許你可以創建一個類來打印所有的證書字段.. – 2017-04-11 00:29:57

+0

...或者你將不得不復制一些代碼(Sun的提供者或bouncycastle)並且包含一個自定義代碼來打印這個擴展(我會這樣做...)。我會盡量在明天提供一些代碼,但同時嘗試這種方法。 – 2017-04-11 00:32:32

+0

好的雨果。我會試試這個。 –