[PR]当たる占い・女性の悩み相談:電話占いならココ!悩むj前に電話で相談

証明書の自動発行(ブラウザに証明書要求を作らせる)

ブラウザで証明書要求を作り、CAで署名、証明書の発行をしてもらって送り返してもらうことが出来ます。
ここでは、IEとNetscapeで証明書要求を作成し、それにOpenSSLのCAで署名する方法と、
署名された証明書をブラウザに自動でImportする方法を説明します。

なお、実際に実装するときにはhttpサーバでCGIを書く必要があると思います。が。
私の書いたコードはしょぼいので、ここには載せません。

Netscapeで証明書要求を作成する
CAから発行された証明書をNetscapeで受け取る
IEで証明書要求を作成する
CAから発行された証明書をIEで受け取る

2000/12/13 更新


Netscapeで証明書要求を作成する

こんなページを作ります。

<html>
<head>
<META http-equiv="Content-Type" content="text/html;
charset=EUC-JP"></head>
証明書を作成するユーザの情報を入力してください<br>

<br>
<FORM method="POST" ACTION="newcertnn"><INPUT TYPE="hidden"
NAME="password">country<br>
<INPUT NAME="country" VALUE="JP"><br>
state<br>
<INPUT NAME="state" VALUE="Tokyo"><br>
city<br>
<INPUT NAME="local" VALUE="Shinjuku-ku"><br>
company<br>
<INPUT NAME="company" VALUE="Internet Widget, Inc."><br>
unit<br>
<INPUT NAME="unit" VALUE="."><br>
NAME<br>
<INPUT NAME="name" VALUE="hoge"><br>
Mail<br>
<INPUT NAME="mailaddr" VALUE="hoge@local.net"><br>
<keygen name="spkac" challenge="challengepw"><br>
ボタン押してね<br>
<INPUT TYPE="submit" VALUE="実行"><br>
</html>

これで、Submitすると、spkac="xxxxxxxx....."と言う形で、
SPKAC(Signed Public Key And Challenge)形式のデータがサーバに送られるの
で、
他のデータと一緒にして、OpenSSLのコマンドで署名します。

まず、こんなファイルを作ります。

$cat user.dat
countryName = JP
stateOrProvinceName = Tokyo
localityName = Shinjuku-ku
0.organizationName = Internet Widget, Inc.
organizationalUnitName = .
commonName = hoge
emailAddress = hoge@local.net
SPKAC=MIG/MGswXDANBgkqhkiG9w0BAQEFAANLADBIAkEA1IwWWZp1gkUWNrntqzDeEByoxzjT8llm2rNf4HDBkWzgDSQ
alDDIBEX7MQKI/TxRpphYQB2/t7E+0PF+GfZ0IQIDAQABFgtjaGFsbGVuZ2VwdzANBgkqhkiG9w0BAQQFAANBAJUBOVO3
UwTkTKvuR05K4mBowXaCMadrN8xq+Z+yhFNJ6ZzLpMb7mYOR8k9FMZnS5A=

最後の行は送られたデータです。一行にする必要があります。
また、"SPKAC="の部分は自分で付ける必要があります。

で、OpenSSLのCAで署名します。
$ openssl ca -batch -config myca.cnf-policy policy_anything -out
usercert.pem -days 365
  -spkac user.dat

コマンドの意味は、
・証明書を作る。
・非対話形式で行う。
・CAの設定ファイルはmyca.cnfを使う。
・証明書のポリシーはpolicy_anything(myca.cnf中にでてくる)
・出力ファイル名は usercert.pem
・証明書の期限は365日後
・user.datというSPKAC形式のファイルを署名する。

CAの秘密鍵のパスフレーズを入力するとできあがり。
usercert.pemが新しい証明書です。



Netscapeで証明書を受け付ける

基礎知識
pem形式の証明書からder形式の証明書への変換

$ openssl x509 -infrom pem -in cert.pem -outform der -out cert.der
で、cert.pemからcert.derにしてくれる。
中身を確認するには、
$ openssl x509 -inform der -in cert.der -text
でおっけ

・ユーザの証明書の場合
 Content-type:application/x-x509-user-cert
 Content-Disposition:filename="cert.crt"

 CGIで、上のようなヘッダーをつけて
 DER形式の証明書をバイナリで送りつければ、
 NN側で取り込んでくれる。
 ただし、NNで証明書リクエストを作成した場合のみ。
 OpenSSLで鍵ペアと証明書を作って、PKCS#12形式に
 した場合は自動取り込み出来ないので、一旦ダウンロード
 した後でNNにインポートする必要がある。

・CAの証明書の場合
 Content-type:application/x-x509-ca-cert

 CGIで、上のようなヘッダーをつけて
 DER形式の証明書をバイナリで送りつければ、
 NN側で取り込んでくれる。

・他のユーザの証明書の場合
 Content-type:application/x-x509-email-cert

 CGIで、上のようなヘッダーをつけて
 DER形式の証明書をバイナリで送りつければ、
 NN側で取り込んでくれる。

取り込んだ証明書の確認は、Communicatorの「セキュリティ」ボタンを押して、
証明書→本人とかでできる。

参考
http://home.netscape.com/eng/security/comm4-cert-download.html
 



IEで証明書要求を作成する

IEで証明書関連の動作をさせる場合は、まずDLLをダウンロードして
スクリプト内でオブジェクトを作成する必要があります。
必要なDLLの名前はxenroll.dllです。msdnのページかどこかで手に入れてください。

その後、証明書要求に必要な個人情報(DN、メールアドレス等)を変数に入れて
CreatePKCS10と言う関数を実行することによってPKCS#10証明書要求を
作成することが出来ます。
その際に、秘密鍵をブラウザで持つように作るか、スマートカード用に作るか等を指定する
CSPの指定)事や、鍵長の指定、要求で使用するハッシュアルゴリズムの指定等
が可能です。

-要求を作成するページの例-

−はまったところー
CreatePKCS10(DN,Purpose)で、DNに入れる文字列の中に","が入っていたため、
 スクリプトエラー 80092023が出まくった。
 あと、Purposeに入れる文字列が判らなかったため、
 80092002もいっぱい出た。これで一日強はまった。

 Purposeに入れる文字列はこんな感じ。らしい。
   <SELECT NAME="UsageOID">
            <OPTION SELECTED VALUE="1.3.6.1.5.5.7.3.2"> Client Authentication
            <OPTION VALUE="1.3.6.1.5.5.7.3.4"> E-Mail Protection
            <OPTION VALUE="1.3.6.1.5.5.7.3.1"> Server Authentication
            <OPTION VALUE="1.3.6.1.5.5.7.3.3"> Code Signing
            <OPTION VALUE="1.3.6.1.5.5.7.3.8"> Time StampSigning
          </SELECT>
 



IEで証明書を受け付ける

まず、CA側で証明書をPKCS#7形式に変換する。

# openssl crl2pkcs7 -certfile newcert.pem -nocrl -out new.p7c

で、このp7cファイルをVBScriptといっしょにブラウザに送り返します。
その際に、証明書要求を作成したときと同じようにオブジェクトを作成する必要があります。
-CGIで送り返すページの例-
参考)http://msdn.microsoft.com/library/psdk/certsrv/xen_abus_723p.htm

でできあがり。
CreatePKCS10でリクエストをつくった時に指定した、
Usageとかは効いているみたいだけど、よくわからん。
作るときのプロパティで、ブラウザでの認証に使うかどうかは変更できた。

オブジェクト名.KeySpec=1; /* = AT_KEYEXCHANGE */ ほかには、AT_SIGNATURE
もある。
オブジェクト名.LimitExchangeKeyToEncipherment=false;

certHelper.GenKeyFlags = 1024<<16;
で、鍵長を決めれる。(the upper 16 bits of GenKeyFlags) だって。

certHelper.GenKeyFlags |= 1; /* CRYPT_EXPORTABLE */
にすると、秘密鍵のExportableフラグが立つので、
秘密鍵のバックアップが取れるようになる。

certHelper.HashAlgorithm = "SHA1"; /* or MD2,MD5 */
なんて設定も可能。ただしこれは要求のハッシュ。
証明書のハッシュはCAのポリシーによる

でおけ。ブラウザの個人鍵のとこにもとった証明書が表示される。



IE Certificate requesting script example

<HTML><HEAD><TITLE>Client Certificate Request</TITLE>
<META HTTP-EQUIV="Cache-Control" CONTENT="no cache">
<META HTTP-EQUIV="Pragma" CONTENT="no cache">
<META HTTP-EQUIV="Expires" CONTENT="0">

        <!OBJECT
        classid="clsid:43F8F289-7A20-11D0-8F06-00C04FC295E1"
        CODEBASE="/xenroll.cab#Version=5,102,1680,101"
        id=certHelper>

           <!-- JavaScript or Visual Basic will work. -->
           <SCRIPT LANGUAGE="JavaScript">
           <!---

           function GenReq ()
           {
               var szName = "";

                 /* personal information */
                   szName = "C=" + document.GenReqForm.countryName.value;
                   szName = szName + ",S=" + document.GenReqForm.stateOrProvinceName.value;
                   szName = szName + ",L=" + document.GenReqForm.localityName.value;
                   szName = szName + ",O=" + document.GenReqForm.organizationName.value;
                   szName = szName + ",OU=" + document.GenReqForm.organizationalUnitName.value;
                   szName = szName + ",CN=" + document.GenReqForm.commonName.value;
                   szName = szName + ",Email=" + document.GenReqForm.Email.value;
                   alert("szName is " + szName);

                /* key hash alg */
                certHelper.HashAlgorithm = "SHA1"; /* or MD2,MD5 */

                /* key usage , for exchange */
                szPurpose = "1.3.6.1.5.5.7.3.2";
                certHelper.KeySpec=1; /* = AT_KEYEXCHANGE */
                certHelper.LimitExchangeKeyToEncipherment=false;

                /* key length */
                certHelper.GenKeyFlags = 1024<<16;

                /* is key exportable ? */
                certHelper.GenKeyFlags |= document.GenReqForm.ExportF.value;

                /* Provider set */
                alert("CSP is " + document.GenReqForm.useCSP.value);
                certHelper.ProviderName = document.GenReqForm.useCSP.value;

 /* make pkcs10 string */
                szDN = certHelper.CreatePKCS10(szName,szPurpose);

               if (szDN.length > 10 )
               {
                   document.GenReqForm.reqEntry.value = szDN;
                   document.GenReqForm.submit();
               } else {
                   alert("Key Pair Generation failed");
                   window.navigate("/");
               }
           }

           //--->
           </SCRIPT>

</HEAD>
<BODY>

           <CENTER><H3>Generate key pair and client certificate request</H3></CENTER>

           <FORM METHOD=POST ACTION="/cgi-bin/newcertnn"
                NAME="GenReqForm"  onSubmit="GenReq()">
           <TABLE>

           <TR><TD>Country:</TD><TD>
           <INPUT TYPE=TEXT NAME="countryName"  VALUE="JP" SIZE=2>

           </TD></TR><TR><TD>State or Province:</TD><TD>
           <INPUT TYPE=TEXT NAME="stateOrProvinceName" VALUE="Tokyo">

           </TD></TR><TR><TD>City:</TD><TD>
           <INPUT TYPE=TEXT NAME="localityName" VALUE="Shinjuku-ku">

           </TD></TR><TR><TD>Organization:</TD><TD>
           <INPUT TYPE=TEXT NAME="organizationName" VALUE="Internet Widget">

           </TD></TR><TR><TD>Organizational Unit:</TD><TD>
           <INPUT TYPE=TEXT NAME="organizationalUnitName" VALUE=".">

           </TD></TR><TR><TD>Email:</TD><TD>
           <INPUT TYPE=TEXT NAME="Email" VALUE="username@">

           </TD></TR><TR><TD>Common Name:</TD><TD>
           <INPUT TYPE=TEXT NAME="commonName" VALUE="yourname" SIZE=64>

           <INPUT TYPE=HIDDEN NAME="reqEntry" value="noreqEntry">

           </TD></TR><TR><TD>CSP:</TD><TD>
           <SELECT NAME="useCSP">
                <OPTION VALUE="Microsoft Base Cryptographic Provider v1.0">MS Default
                <OPTION VALUE="Schlumberger Cryptographic Service Provider">Schlumberger SmartC
ard
           </SELECT>

           </TD></TR><TR><TD>PrivatekeyExport:</TD><TD>
           <SELECT NAME="ExportF">
                <OPTION VALUE="1">Yes
                <OPTION VALUE="0">No
           </SELECT>

           </TD></TR></TABLE>

           <INPUT TYPE="SUBMIT" name="SUBMIT">
           </FORM>

</BODY></HTML>



IE Certificate Acception C code example

        PRINTHTMLHEADER;
        printf("<HTML><HEAD><TITLE>Client Certificate Request</TITLE>\n");
        printf("<META HTTP-EQUIV=\"Cache-Control\" CONTENT=\"no cache\">\n");
        printf("<META HTTP-EQUIV=\"Pragma\" CONTENT=\"no cache\">\n");
        printf("<META HTTP-EQUIV=\"Expires\" CONTENT=\"0\">\n");
        printf("<OBJECT classid=\"clsid:43F8F289-7A20-11D0-8F06-00C04FC295E1\"\n");
        printf("CODEBASE=\"/xenroll.dll\"\n");
        printf("id=certHelper>\n");
        printf("</OBJECT>\n");
        printf("\n");
        printf("<Script Language=\"VBScript\">\n");
        printf("Public sPKCS7\n");
        printf("sPKCS7=\"\"\n");
        printf("sPKCS7=sPKCS7 & \"-----BEGIN CERTIFICATE-----\" & vbNewLine\n");

        fp = fopen("/usr/local/ca/ca2/cert.p7c","r");
        if(fp == NULL){
                lprint("ssl_sendcert_ie:can't open certfile");
                goto end;
        }
        fgets(buf,BUFLENMAX,fp);
        while(fgets(buf,BUFLENMAX,fp)){
                buf[strlen(buf)-1] = '\0';
                if(!strcmp(buf,"-----END PKCS7-----"))
                        printf("sPKCS7=sPKCS7 & \"-----END CERTIFICATE-----\" & vbNewLine\n");
                else
                        printf("sPKCS7=sPKCS7 & \"%s\" & vbNewLine\n",buf);
        }
        printf("</Script>\n");
        _FCLOSE(fp);

        printf("<Script Language=\"VBScript\">\n");
        printf("Sub Install()\n");
        printf("        Dim sMessage\n");
        printf("        On Error Resume Next\n");
        printf("\n");
        printf("        Alert \"PKCS7 is\" & vbCrLf & sPKCS7\n");
        printf("        Err.Number = 0\n");
        printf("        Call certHelper.AcceptPKCS7(sPKCS7)\n");
        printf("\n");
        printf("If Err.Number = 0 Then\n");
        printf("        Alert \"Success to install\"\n");
        printf("Else\n");
        printf("        If Err.Number=&H80092004 Then 'CRYPT_E_NOT_FOUND\n");
        printf("        ' the private key was not found - most likely this is an attempt to rei
nstall\n");
        printf("                sMessage = \"private key is not found in your db\"\n");
        printf("        Else\n");
        printf("                sMessage = \"unknown_error\"\n");
        printf("        End If\n");
        printf("        Alert sMessage & \":\" & Err.Number & vbCrLf & Err.Description\n");
        printf("End If\n");
        printf("End Sub\n");
        printf("</Script>");
        printf("\n");
        printf("</HEAD>\n");
        printf("\n");
        fflush(stdout);
        printf("<BODY>\n");
        printf("\n");
        printf("<P ID=locPageTitle> <B> 証明書は発行されました </B>\n");
        printf("<!-- Green HR -->\n");
        printf("<Table Border=0 CellSpacing=0 CellPadding=0 Width=100%><TR><TD BgColor=#008080>
\n");
        printf("<Img Src=\"certspc.gif\" Alt=\"\" Height=2 Width=1></TD></TR></Table>\n");
        printf("\n");
        printf("<P ID=locInfo> 要求した証明書は要求者に発行されました。</P>\n"
);
        printf("\n");
        printf("<P><Form Name=UIForm>\n");
        printf("\n");
        printf("<Table Border=0 CellSpacing=0 CellPadding=0>\n");
        printf("\n");
        printf("<TR>");
        printf("<TD><Font size=4><A Href=\"/\" OnClick=Install()>\n");
        printf("<LocID ID=この証明書のインストール</LocID>\n");
        printf("</A></Font></TD>\n");
        printf("\n");
        printf("</TR>\n");
        printf("</Table>\n");
        printf("</Form></P>");
        printf("\n");
        printf("</body>\n");
        printf("</html>\n");
        fflush(stdout);



HOME
[PR]薬用プロアクティブ公式サイト:実力派にきびケア、60日間返金保証