diff options
Diffstat (limited to 'doc/ms3-ca.doc')
-rw-r--r-- | doc/ms3-ca.doc | 398 |
1 files changed, 398 insertions, 0 deletions
diff --git a/doc/ms3-ca.doc b/doc/ms3-ca.doc new file mode 100644 index 0000000000..f8350aadc2 --- /dev/null +++ b/doc/ms3-ca.doc @@ -0,0 +1,398 @@ +Date: Mon, 9 Jun 97 08:00:33 +0200 +From: Holger.Reif@PrakInf.TU-Ilmenau.DE (Holger Reif) +Subject: ms3-ca.doc +Organization: TU Ilmenau, Fak. IA, FG Telematik +Content-Length: 14575 +Status: RO +X-Status: + +Loading client certs into MSIE 3.01 +=================================== + +This document conatains all the information necessary to succesfully set up +some scripts to issue client certs to Microsoft Internet Explorer. It +includes the required knowledge about the model MSIE uses for client +certification and includes complete sample scripts ready to play with. The +scripts were tested against a modified ca program of SSLeay 0.6.6 and should +work with the regular ca program that comes with version 0.8.0. I haven't +tested against MSIE 4.0 + +You can use the information contained in this document in either way you +want. However if you feel it saved you a lot of time I ask you to be as fair +as to mention my name: Holger Reif <reif@prakinf.tu-ilmenau.de>. + +1.) The model used by MSIE +-------------------------- + +The Internet Explorer doesn't come with a embedded engine for installing +client certs like Netscape's Navigator. It rather uses the CryptoAPI (CAPI) +defined by Microsoft. CAPI comes with WindowsNT 4.0 or is installed together +with Internet Explorer since 3.01. The advantage of this approach is a higher +flexibility because the certificates in the (per user) system open +certificate store may be used by other applications as well. The drawback +however is that you need to do a bit more work to get a client cert issued. + +CAPI defines functions which will handle basic cryptographic work, eg. +generating keys, encrypting some data, signing text or building a certificate +request. The procedure is as follows: A CAPI function generates you a key +pair and saves it into the certificate store. After that one builds a +Distinguished Name. Together with that key pair another CAPI function forms a +PKCS#10 request which you somehow need to submit to a CA. Finally the issued +cert is given to a yet another CAPI function which saves it into the +certificate store. + +The certificate store with the user's keys and certs is in the registry. You +will find it under HKEY_CURRENT_USER/Software/Microsoft/Cryptography/ (I +leave it to you as a little exercise to figure out what all the entries mean +;-). Note that the keys are protected only with the user's usual Windows +login password. + +2.) The practical usage +----------------------- + +Unfortunatly since CAPI is a system API you can't access its functions from +HTML code directly. For this purpose Microsoft provides a wrapper called +certenr3.dll. This DLL accesses the CAPI functions and provides an interface +usable from Visual Basic Script. One needs to install that library on the +computer which wants to have client cert. The easiest way is to load it as an +ActiveX control (certenr3.dll is properly authenticode signed by MS ;-). If +you have ever enrolled e cert request at a CA you will have installed it. + +At time of writing certenr3.dll is contained in +http://www.microsoft.com/workshop/prog/security/csa/certenr3.exe. It comes +with an README file which explains the available functions. It is labeled +beta but every CA seems to use it anyway. The license.txt allows you the +usage for your own purposes (as far as I understood) and a somehow limited +distribution. + +The two functions of main interest are GenerateKeyPair and AcceptCredentials. +For complete explanation of all possible parameters see the README file. Here +are only minimal required parameters and their values. + +GenerateKeyPair(sessionID, FASLE, szName, 0, "ClientAuth", TRUE, FALSE, 1) +- sessionID is a (locally to that computer) unique string to correlate the +generated key pair with a cert installed later. +- szName is the DN of the form "C=DE; S=Thueringen; L=Ilmenau; CN=Holger +Reif; 1.2.840.113549.1.9.1=reif@prakinf.tu-ilmenau.de". Note that S is the +abreviation for StateOrProvince. The recognized abreviation include CN, O, C, +OU, G, I, L, S, T. If the abreviation is unknown (eg. for PKCS#9 email addr) +you need to use the full object identifier. The starting point for searching +them could be crypto/objects.h since all OIDs know to SSLeay are listed +there. +- note: the possible ninth parameter which should give a default name to the +certificate storage location doesn't seem to work. Changes to the constant +values in the call above doesn't seem to make sense. You can't generate +PKCS#10 extensions with that function. + +The result of GenerateKeyPair is the base64 encoded PKCS#10 request. However +it has a little strange format that SSLeay doesn't accept. (BTW I feel the +decision of rejecting that format as standard conforming.) It looks like +follows: + 1st line with 76 chars + 2nd line with 76 chars + ... + (n-2)th line with 76 chars + (n-1)th line contains a multiple of 4 chars less then 76 (possible +empty) + (n)th line has zero or 4 chars (then with 1 or 2 equal signs - the + original text's lenght wasn'T a multiple of 3) + The line separator has two chars: 0x0d 0x0a + +AcceptCredentials(sessionID, credentials, 0, FALSE) +- sessionID needs to be the same as while generating the key pair +- credentials is the base64 encoded PKCS#7 object containing the cert. + +CRL's and CA certs are not required simply just the client cert. (It seems to +me that both are not even checked somehow.) The only format of the base64 +encoded object I succesfully used was all characters in a very long string +without line feeds or carriage returns. (Hey, it doesn't matter, only a +computer reads it!) + +The result should be S_OK. For error handling see the example that comes with +certenr3.dll. + +A note about ASN.1 character encodings. certenr3.dll seems to know only about +2 of them: UniversalString and PrintableString. First it is definitely wrong +for an email address which is IA5STRING (checked by ssleay's ca). Second +unfortunately MSIE (at least until version 3.02) can't handle UniversalString +correctly - they just blow up you cert store! Therefore ssleay's ca (starting +from version 0.8.0) tries to convert the encodings automatically to IA5STRING +or TeletexString. The beef is it will work only for the latin-1 (western) +charset. Microsoft still has to do abit of homework... + +3.) An example +-------------- + +At least you need two steps: generating the key & request and then installing +the certificate. A real world CA would have some more steps involved, eg. +accepting some license. Note that both scripts shown below are just +experimental state without any warrenty! + +First how to generate a request. Note that we can't use a static page because +of the sessionID. I generate it from system time plus pid and hope it is +unique enough. Your are free to feed it through md5 to get more impressive +ID's ;-) Then the intended text is read in with sed which inserts the +sessionID. + +-----BEGIN ms-enroll.cgi----- +#!/bin/sh +SESSION_ID=`date '+%y%m%d%H%M%S'`$$ +echo Content-type: text/html +echo +sed s/template_for_sessId/$SESSION_ID/ <<EOF +<HTML><HEAD> +<TITLE>Certificate Enrollment Test Page</TITLE> +</HEAD><BODY> + +<OBJECT + classid="clsid:33BEC9E0-F78F-11cf-B782-00C04FD7BF43" + codebase=certenr3.dll + id=certHelper + > +</OBJECT> + +<CENTER> +<H2>enrollment for a personal cert</H2> +<BR><HR WIDTH=50%><BR><P> +<FORM NAME="MSIE_Enrollment" ACTION="ms-gencert.cgi" ENCTYPE=x-www-form- +encoded METHOD=POST> +<TABLE> + <TR><TD>Country</TD><TD><INPUT NAME="Country" VALUE=""></TD></TR> + <TR><TD>State</TD><TD><INPUT NAME="StateOrProvince" VALUE=""></TD></TR> + <TR><TD>Location</TD><TD><INPUT NAME="Location" VALUE=""></TD></TR> + <TR><TD>Organization</TD><TD><INPUT NAME="Organization" +VALUE=""></TD></TR> + <TR><TD>Organizational Unit</TD> + <TD><INPUT NAME="OrganizationalUnit" VALUE=""></TD></TR> + <TR><TD>Name</TD><TD><INPUT NAME="CommonName" VALUE=""></TD></TR> + <TR><TD>eMail Address</TD> + <TD><INPUT NAME="EmailAddress" VALUE=""></TD></TR> + <TR><TD></TD> + <TD><INPUT TYPE="BUTTON" NAME="submit" VALUE="Beantragen"></TD></TR> +</TABLE> + <INPUT TYPE="hidden" NAME="SessionId" VALUE="template_for_sessId"> + <INPUT TYPE="hidden" NAME="Request" VALUE=""> +</FORM> +<BR><HR WIDTH=50%><BR><P> +</CENTER> + +<SCRIPT LANGUAGE=VBS> + Dim DN + + Sub Submit_OnClick + Dim TheForm + Set TheForm = Document.MSIE_Enrollment + sessionId = TheForm.SessionId.value + reqHardware = FALSE + C = TheForm.Country.value + SP = TheForm.StateOrProvince.value + L = TheForm.Location.value + O = TheForm.Organization.value + OU = TheForm.OrganizationalUnit.value + CN = TheForm.CommonName.value + Email = TheForm.EmailAddress.value + szPurpose = "ClientAuth" + doAcceptanceUINow = FALSE + doOnline = TRUE + + DN = "" + + Call Add_RDN("C", C) + Call Add_RDN("S", SP) + Call Add_RDN("L", L) + Call Add_RDN("O", O) + Call Add_RDN("OU", OU) + Call Add_RDN("CN", CN) + Call Add_RDN("1.2.840.113549.1.9.1", Email) + ' rsadsi + ' pkcs + ' pkcs9 + ' eMailAddress + On Error Resume Next + sz10 = certHelper.GenerateKeyPair(sessionId, _ + FALSE, DN, 0, ClientAuth, FASLE, TRUE, 1)_ + theError = Err.Number + On Error Goto 0 + if (sz10 = Empty OR theError <> 0) Then + sz = "The error '" & Hex(theError) & "' occurred." & chr(13) & _ + chr(10) & "Your credentials could not be generated." + result = MsgBox(sz, 0, "Credentials Enrollment") + Exit Sub + else + TheForm.Request.value = sz10 + TheForm.Submit + end if + End Sub + + Sub Add_RDN(sn, value) + if (value <> "") then + if (DN <> "") then + DN = DN & "; " + end if + DN = DN & sn & "=" & value + end if + End Sub +</SCRIPT> +</BODY> +</HTML> +EOF +-----END ms-enroll.cgi----- + +Second, how to extract the request and feed the certificate back? We need to +"normalize" the base64 encoding of the PKCS#10 format which means +regenerating the lines and wrapping with BEGIN and END line. This is done by +gawk. The request is taken by ca the normal way. Then the cert needs to be +packed into a PKCS#7 structure (note: the use of a CRL is necessary for +crl2pkcs7 as of version 0.6.6. Starting with 0.8.0 it it might probably be +ommited). Finally we need to format the PKCS#7 object and generate the HTML +text. I use two templates to have a clearer script. + +1st note: postit2 is slightly modified from a program I found at ncsa's ftp +site. Grab it from http://www.easterngraphics.com/certs/IX9704/postit2.c. You +need utils.c from there too. + +2nd note: I'm note quite sure wether the gawk script really handles all +possible inputs for the request right! Today I don't use this construction +anymore myself. + +3d note: the cert must be of version 3! This could be done with the nsComment +line in ssleay.cnf... + +------BEGIN ms-gencert.cgi----- +#!/bin/sh +FILE="/tmp/"`date '+%y%m%d%H%M%S'-`$$ +rm -f "$FILE".* + +HOME=`pwd`; export HOME # as ssleay.cnf insists on having such an env var +cd /usr/local/ssl #where demoCA (as named in ssleay.conf) is located + +postit2 -s " " -i 0x0d > "$FILE".inp # process the FORM vars + +SESSION_ID=`gawk '$1 == "SessionId" { print $2; exit }' "$FILE".inp` + +gawk \ + 'BEGIN { \ + OFS = ""; \ + print "-----BEGIN CERTIFICATE REQUEST-----"; \ + req_seen=0 \ + } \ + $1 == "Request" { \ + req_seen=1; \ + if (length($2) == 72) print($2); \ + lastline=$2; \ + next; \ + } \ + { \ + if (req_seen == 1) { \ + if (length($1) >= 72) print($1); \ + else if (length(lastline) < 72) { \ + req_seen=0; \ + print (lastline,$1); \ + } \ + lastline=$1; \ + } \ + } \ + END { \ + print "-----END CERTIFICATE REQUEST-----"; \ + }' > "$FILE".pem < "$FILE".inp + +ssleay ca -batch -in "$FILE".pem -key passwd -out "$FILE".out +ssleay crl2pkcs7 -certfile "$FILE".out -out "$FILE".pkcs7 -in demoCA/crl.pem + +sed s/template_for_sessId/$SESSION_ID/ <ms-enroll2a.html >"$FILE".cert +/usr/local/bin/gawk \ + 'BEGIN { \ + OFS = ""; \ + dq = sprintf("%c",34); \ + } \ + $0 ~ "PKCS7" { next; } \ + { \ + print dq$0dq" & _"; \ + }' <"$FILE".pkcs7 >> "$FILE".cert +cat ms-enroll2b.html >>"$FILE".cert + +echo Content-type: text/html +echo Content-length: `wc -c "$FILE".cert` +echo +cat "$FILE".cert +rm -f "$FILE".* +-----END ms-gencert.cgi----- + +----BEGIN ms-enroll2a.html---- +<HTML><HEAD><TITLE>Certificate Acceptance Test Page</TITLE></HEAD><BODY> + +<OBJECT + classid="clsid:33BEC9E0-F78F-11cf-B782-00C04FD7BF43" + codebase=certenr3.dll + id=certHelper + > +</OBJECT> + +<CENTER> +<H2>Your personal certificate</H2> +<BR><HR WIDTH=50%><BR><P> +Press the button! +<P><INPUT TYPE=BUTTON VALUE="Nimm mich!" NAME="InstallCert"> +</CENTER> +<BR><HR WIDTH=50%><BR> + +<SCRIPT LANGUAGE=VBS> + Sub InstallCert_OnClick + + sessionId = "template_for_sessId" +credentials = "" & _ +----END ms-enroll2a.html---- + +----BEGIN ms-enroll2b.html---- +"" + On Error Resume Next + result = certHelper.AcceptCredentials(sessionId, credentials, 0, +FALSE) + if (IsEmpty(result)) Then + sz = "The error '" & Err.Number & "' occurred." & chr(13) & +chr(10) & "This Digital ID could not be registered." + msgOut = MsgBox(sz, 0, "Credentials Registration Error") + navigate "error.html" + else + sz = "Digital ID successfully registered." + msgOut = MsgBox(sz, 0, "Credentials Registration") + navigate "success.html" + end if + Exit Sub + End Sub +</SCRIPT> +</BODY> +</HTML> +----END ms-enroll2b.html---- + +4.) What do do with the cert? +----------------------------- + +The cert is visible (without restarting MSIE) under the following menu: +View->Options->Security->Personal certs. You can examine it's contents at +least partially. + +To use it for client authentication you need to use SSL3.0 (fortunately +SSLeay supports it with 0.8.0). Furthermore MSIE is told to only supports a +kind of automatic selection of certs (I personally wasn't able to test it +myself). But there is a requirement that the issuer of the server cert and +the issuer of the client cert needs to be the same (according to a developer +from MS). Which means: you need may more then one cert to talk to all +servers... + +I'm sure we will get a bit more experience after ApacheSSL is available for +SSLeay 0.8.8. + + +I hope you enjoyed reading and that in future questions on this topic will +rarely appear on ssl-users@moncom.com ;-) + +Ilmenau, 9th of June 1997 +Holger Reif <reif@prakinf.tu-ilmenau.de> +-- +read you later - Holger Reif +---------------------------------------- Signaturprojekt Deutsche Einheit +TU Ilmenau - Informatik - Telematik (Verdamp lang her) +Holger.Reif@PrakInf.TU-Ilmenau.DE Alt wie ein Baum werden, um ueber +http://Remus.PrakInf.TU-Ilmenau.DE/Reif/ alle 7 Bruecken gehen zu koennen + |