Terry.Li-彬

          虛其心,可解天下之問;專其心,可治天下之學(xué);靜其心,可悟天下之理;恒其心,可成天下之業(yè)。

            BlogJava :: 首頁 :: 新隨筆 :: 聯(lián)系 :: 聚合  :: 管理 ::
            143 隨筆 :: 344 文章 :: 130 評論 :: 0 Trackbacks
          前幾次我已經(jīng)基本上把如何做CA所需要的基礎(chǔ)知識講得差不多了,今天直接講如何用Java程序來實現(xiàn)一個CA應(yīng)該就不是什么太困難的事情了.

              要做CA,第一步要準備好自己的證書和私鑰.私鑰如何從文件里面讀取出來前面已經(jīng)講過了.從文件系統(tǒng)中讀出證書的代碼如下:

              CertificateFactory certCF = CertificateFactory.getInstance("X.509");
              X509Certificate caCert = certCF.generateCertificate(certBIS);

              這里cerBIS是一個InputStream類型的對象.例如一個標準的X509v3格式的證書文件所形成的輸入流.

              第二步就是從用戶那里獲取輸入,然后構(gòu)造主體名稱結(jié)構(gòu)DN,如何構(gòu)造DN上次已經(jīng)說過了,如何從用戶那里獲取輸入,這個不在本文討論范圍之內(nèi).

              下一步就是獲取用戶的公鑰,好和他所需要的證書對應(yīng)起來.也有不少CA的做法就是在這里替用戶現(xiàn)場生成一對密鑰對,然后把公鑰放到證書中簽發(fā)給用戶.這個應(yīng)該看實際需要選擇合適的方式.

              現(xiàn)在一切信息都已經(jīng)準備好了,可以簽發(fā)證書了,下面的代碼說明了這個過程:

              //構(gòu)造一個證書生成器對象

              X509V3CertificateGenerator certGen = new X509V3CertificateGenerator();

              // 從CA的證書中獲取簽發(fā)者的主體名稱(DN)
              // 這里有一點小技巧,我們要把JCE中定義的
              // 用來表示DN的對象X500Principal轉(zhuǎn)化成在
              // BC Provider中的相應(yīng)的對象X509Name
              // 先從CA的證書中讀取出CA的DN進行DER編碼
              DERInputStream dnStream =
                           new DERInputStream(
                new ByteArrayInputStream(
                 caCert.getSubjectX500Principal().
                  getEncoded()));
              // 馬上又從編碼后的字節(jié)流中讀取DER編碼對象
              DERConstructedSequence  dnSequence =
               (DERConstructedSequence)dnStream.readObject();
              // 利用讀取出來的DER編碼對象創(chuàng)建X509Name
              // 對象,并設(shè)置為證書生成器中的"簽發(fā)者DN"
              certGen.setIssuerDN(new X509Name(dnSequence));
              // 設(shè)置好證書生成器中的"接收方DN"
              certGen.setSubjectDN(subjectDN);
              // 設(shè)置好一些擴展字段,包括簽發(fā)者和
              // 接收者的公鑰標識
              certGen.addExtension(X509Extensions.SubjectKeyIdentifier, false,
              createSubjectKeyId(keyToCertify));
              certGen.addExtension(X509Extensions.AuthorityKeyIdentifier, false,
              createAuthorityKeyId(caCert.getPublicKey()));
              // 設(shè)置證書的有效期和序列號
              certGen.setNotBefore(startDate);
              certGen.setNotAfter(endDate);
              certGen.setSerialNumber(serialNumber);
              // 設(shè)置簽名算法,本例中使用MD5hash后RSA
              // 簽名,并且設(shè)置好主體的公鑰
              certGen.setSignatureAlgorithm("MD5withRSA");
              certGen.setPublicKey(keyToCertify);

              // 如果以上一切都正常地話,就可以生成證書了
              X509Certificate cert = null;
              cert = certGen.generateX509Certificate(caPrivateKey);

              這里是上面用到的生成簽發(fā)者公鑰標識的函數(shù): 

              protected AuthorityKeyIdentifier createAuthorityKeyId(PublicKey pubKey)
              {
              AuthorityKeyIdentifier authKeyId = null;

              try
              {
              ByteArrayInputStream bIn = new ByteArrayInputStream(pubKey.getEncoded());
              SubjectPublicKeyInfo info = new SubjectPublicKeyInfo(
                  (DERConstructedSequence)new DERInputStream(bIn).readObject());
              authKeyId = new AuthorityKeyIdentifier(info);
              }
              catch (IOException e)
              {
              System.err.println("Error generating SubjectKeyIdentifier:  " +
                  e.toString());
              System.exit(1);
              }

              return authKeyId;
              }

              生成主體公鑰標識的函數(shù)和上面的類似,把AuthorityKeyIdentifier替換成SubjectKeyIdentifier就可以了.

              這里要注意的是,CA的公鑰也是在一份證書里,這種證書的特點是簽發(fā)者DN和接收者DN一樣,也就是說,這種證書是CA自己給自己頒發(fā)的證書,也就是"自 簽名證書",它上面的公鑰是CA自身的公鑰,用來簽名的私鑰就是該公鑰對應(yīng)的私鑰.一般每個CA都要有這么一份證書,除非該CA不是根CA,即它的權(quán)威性 不是由它自己證明,而是由它的上級CA證明.但是,最后總歸要有一個根CA,它為各個安全應(yīng)用程序的用戶所信賴.

              到這里我們已經(jīng)把CA最基本的功能如何用Java實現(xiàn)講完了,下一次講如何從PKCS#10格式證書請求文件中讀取出用戶信息,然后直接簽發(fā)公鑰.
          posted on 2008-02-13 22:13 禮物 閱讀(566) 評論(0)  編輯  收藏

          只有注冊用戶登錄后才能發(fā)表評論。

          網(wǎng)站導(dǎo)航:
           
          主站蜘蛛池模板: 舟曲县| 云和县| 睢宁县| 合肥市| 大余县| 万载县| 邯郸市| 丰顺县| 铜山县| 买车| 西平县| 渭源县| 横峰县| 正阳县| 砚山县| 山西省| 古田县| 修武县| 苍梧县| 治县。| 罗平县| 云南省| 芮城县| 繁昌县| 夏河县| 莱芜市| 绍兴县| 通辽市| 镇巴县| 鄢陵县| 航空| 简阳市| 灵宝市| 巴林左旗| 金堂县| 同江市| 纳雍县| 息烽县| 汉阴县| 青川县| 保德县|