论坛: 编程破解 标题: [转]在jsp中读取数字证书 复制本贴地址    
作者: authen [authen]    论坛用户   登录
在JSP中读取数字证书

1、概述
    数字证书是一个经证书授权中心数字签名的包含公开密钥拥有者信息和公开密钥的文件。最简单的证书包含一个公开密钥、名称以及证书授权中心的数字签名。一般情况下证书中还包括密钥的有效时间,发证机关(证书授权中心)的名称,该证书的序列号等信息,证书的格式遵循ITUT X.509国际标准。

2、证书的格式
X.509目前有三个版本:V1、V2和V3。
X.509 V1和V2证书所包含的主要内容如下:
证书版本号(Version):版本号指明X.509证书的格式版本,现在的值可以为0、1、2,也为将来的版本进行了预定义。
      证书序列号(SerialNumber):序列号指定由CA分配给证书的唯一的数字型标识符。当证书被取消时,实际上是将此证书的序列号放入由CA签发的CRL中,这也是序列号唯一的原因。
      签名算法标识符(Signature):签名算法标识用来指定由CA签发证书时所使用的签名算法。算法标识符用来指定CA签发证书时所使用的公开密钥算法和hash算法,须向国际知名标准组织(如ISO)注册。
      签发机构名(Issuer):此域用来标识签发证书的CA的X.500 DN名字。包括国家、省市、地区、组织机构、单位部门和通用名。
    有效期(Validity):指定证书的有效期,包括证书开始生效的日期和时间以及失效的日期和时间。每次使用证书时,需要检查证书是否在有效期内。
    证书用户名(Subject):指定证书持有者的X.500唯一名字。包括国家、省市、地区、组织机构、单位部门和通用名,还可包含email地址等个人信息等
    证书持有者公开密钥信息(subjectPublicKeyInfo):证书持有者公开密钥信息域包含两个重要信息:证书持有者的公开密钥的值;公开密钥使用的算法标识符。此标识符包含公开密钥算法和hash算法。
    签发者唯一标识符(Issuer Unique Identifier):签发者唯一标识符在第2版加入证书定义中。此域用在当同一个X.500名字用于多个认证机构时,用一比特字符串来唯一标识签发者的X.500名字。可选。
    证书持有者唯一标识符(Subject Unique Identifier):持有证书者唯一标识符在第2版的标准中加入X.509证书定义。此域用在当同一个X.500名字用于多个证书持有者时,用一比特字符串来唯一标识证书持有者的X.500名字。可选。
    签名值(Issuer's Signature):证书签发机构对证书上述内容的签名值。
X.509 V3证书是在v2的基础上一标准形式或普通形式增加了扩展项,以使证书能够附带额外信息。标准扩展是指由X.509 V3版本定义的对V2版本增加的具有广泛应用前景的扩展项,任何人都可以向一些权威机构,如ISO,来注册一些其他扩展,如果这些扩展项应用广泛,也许以后会成为标准扩展项。

3、J2EE结构下的数字证书应用与开发
(1) Keystore概念
Java中,Keystore用于收集密钥和证书。Keysotre通常存放在文件中,也可以存放在数据库和LDAP服务器中。通常在keystore中有两类实体:可信证书和密钥。为保险起见,可以使用其他提供者的keystore,如Bouncy Castle的keystore。
(2) Keytool概念
Keytool是JDK所带的一个程序,它管理keystore,而且可以产生证书。举例如下:
  产生一个别名为test的keystore:keytool -genkey -alias test
  输出证书:keytool -export -alias test -file test.cer
  查看keystore内容:keytool -v �Clist
(3) java中的证书类
  在开发中使用证书时,需要JDK中的三个类:Certificate、X509Certificate和CertificateFactory。这些类都封装在java.security.cert中。
    java.security.cert.Certificate是封装证书的一个抽象类,常用的方法有getPublicKey()和verify()方法。
java.security.certX509.Certificate提供了处理X509证书的方法。
java.security.cert. CertificateFactory用来产生证书对象。

4、从证书文件读取数字证书
  证书对象的属性:
  Version  版本
  Subject  主体
  Signature algorithm  签名算法,默认下keytool产生证书使用SHA1with―DSA算法
  Public key          公钥
  Validity            有效期
  Issuer            发布者,一般是自签证书,所以与主体相同
  Serial number      序列号
  算法和签名

  为方便起见,假设证书文件(gao.cer)存放在d:盘目录下,下面一段jsp程序读该证书并输出版本,主体,有效期等信息
  程序如下所示:
  CertInfo.java
import java.io.*;
import java.security.cert.*;
import java.security.cert.CertificateFactory;
public class CertInfo
{  static String issue,after,before,subject;
  static String serialno,signalg;
  static int version;
      public void Init()  throws Exception{
                CertificateFactory certFactory=CertificateFactory.getInstance("X.509");
FileInputStream fis=new FileInputStream("d://高翔.cer");
X509Certificate cert=(X509Certificate)certFactory.generateCertificate(fis);

fis.close();
                issue=cert.getIssuerDN().toString();
                subject=cert.getSubjectDN().getName();
                after=cert.getNotAfter().toString();
                before=cert.getNotBefore().toString();
                version=cert.getVersion();
                serialno=cert.getSerialNumber().toString();
                signalg=cert.getSigAlgName();
  }
      public String getIssue(){
        return issue;
      }

      public String getAfter(){
        return after;
      }

      public String getBefore(){
        return before;
      }

      public String getSerial(){
        return serialno;
      }

      public String getsignalg(){
        return signalg;
      }

      public String getsubject(){
        return subject;
      }

      public String getversion(){
              return ("ver:"+version);
            }


public static void main(String[] args) throws Exception
{
                CertInfo c=new CertInfo();
                c.Init();
System.out.println(c.getBefore());
System.out.println(version);
System.out.println(c.getversion());
System.out.println(issue);
System.out.println(c.getsubject());
                System.out.println(c.getsignalg());
}
}
read.jsp
<%@ page contentType="text/html; charset=gb2312"    %>
<%@ page language="java"                            %>
<html>
<head>
<title>JSP中读取X509数字证书</title>
</head>
<body>
<jsp:useBean id="cert" scope="page" class="CertInfo"/>
<% cert.Init();%>
序列号:<%=cert.getSerial()%><br>
发布人:<%=cert.getIssue()%><br>
发布主体:<%=cert.getsubject()%><br>
版本号:<%=cert.getversion()%><br>
签名算法:<%=cert.getsignalg()%><br>
有效期:<%=cert.getAfter()%>-----<%=cert.getBefore()%><br>

</body>
</html>
程序在jrun3.0下调试通过。

5、应用SSL协议从HTTP头读证书
该程序假设客户与服务器端已经建立了基于SSL的安全连接,服务器端的Servlet读取客户端X509证书,该程序把用户的请求局限为安全连接。

import java.io.*;
import javax.servlet.*;
import javax.servlet.http.*;
import java.security.cert.*; // For X509Certificate


public class SecurityInfo extends HttpServlet {
  public void doGet(HttpServletRequest request,
                    HttpServletResponse response)
      throws ServletException, IOException {
    // Redirect non-SSL requests to the SSL equivalent.
    if (request.getScheme().equalsIgnoreCase("http")) {
      String origURL = request.getRequestURL().toString();
      String newURL = httpsURL(origURL);
      String formData = request.getQueryString();
      if (formData != null) {
        newURL = newURL + "?" + formData;
      }
      response.sendRedirect(newURL);
    } else {
      String currentURL = request.getRequestURL().toString();
      String formData = request.getQueryString();
 
      PrintWriter out = response.getWriter();
      String docType =
        "<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.0 " +
        "Transitional//EN\">\n";
      String title = "Security Info";
      out.println
        (docType +
        "<HTML>\n" +
        "<HEAD><TITLE>" + title +
        "</TITLE></HEAD>\n" +
        "<BODY BGCOLOR=\"#FDF5E6\">\n" +
        "<H1>" + title + "</H1>\n" +
        "<UL>\n" +
        "  <LI>URL: " + currentURL + "\n" +
        "  <LI>Data: " + formData);
      boolean isSecure = request.isSecure();
      if (isSecure) {
        String keyAttribute =
          "javax.servlet.request.key_size";
                Integer keySize =
          (Integer)request.getAttribute(keyAttribute);
        String sizeString =
          replaceNull(keySize, "Unknown");
        String cipherAttribute =
          "javax.servlet.request.cipher_suite";
       
        String cipherSuite =
          (String)request.getAttribute(cipherAttribute);
        String cipherString =
          replaceNull(cipherSuite, "Unknown");
        String certAttribute =
          "javax.servlet.request.X509Certificate";
       
        X509Certificate certificate =
          (X509Certificate)request.getAttribute(certAttribute);
        String certificateString =
          replaceNull(certificate, "None");
        out.println
          ("  <LI>SSL: true\n" +
          "  <UL>\n" +
          "    <LI>Key Size: " + sizeString + "\n" +
          "    <LI>Cipher Suite: " + cipherString + "\n" +
          "    <LI>Client Certificate: " +
          certificateString + "\n" +
          "  </UL>");
      }
      out.println
        ("</UL>\n" +
        "</BODY></HTML>");
    }
  }

  // Given http://blah, return https://blah.
 
  private String httpsURL(String origURL) {
    int index = origURL.indexOf(":");
    StringBuffer newURL = new StringBuffer(origURL);
    newURL.insert(index, 's');
    return(newURL.toString());
  }

  // If the first argument is null, return the second argument.
  // Otherwise, convert first argument to a String and
  // return that String.

  private String replaceNull(Object obj, String fallback) {
    if (obj == null) {
      return(fallback);
    } else {
      return(obj.toString());
    }
  }
}


地主 发表时间: 05-07-21 10:03

论坛: 编程破解

20CN网络安全小组版权所有
Copyright © 2000-2010 20CN Security Group. All Rights Reserved.
论坛程序编写:NetDemon

粤ICP备05087286号