diff options
Diffstat (limited to 'src/lib/libssl/src/doc/ms3-ca.doc')
| -rw-r--r-- | src/lib/libssl/src/doc/ms3-ca.doc | 398 |
1 files changed, 398 insertions, 0 deletions
diff --git a/src/lib/libssl/src/doc/ms3-ca.doc b/src/lib/libssl/src/doc/ms3-ca.doc new file mode 100644 index 0000000000..f8350aadc2 --- /dev/null +++ b/src/lib/libssl/src/doc/ms3-ca.doc | |||
| @@ -0,0 +1,398 @@ | |||
| 1 | Date: Mon, 9 Jun 97 08:00:33 +0200 | ||
| 2 | From: Holger.Reif@PrakInf.TU-Ilmenau.DE (Holger Reif) | ||
| 3 | Subject: ms3-ca.doc | ||
| 4 | Organization: TU Ilmenau, Fak. IA, FG Telematik | ||
| 5 | Content-Length: 14575 | ||
| 6 | Status: RO | ||
| 7 | X-Status: | ||
| 8 | |||
| 9 | Loading client certs into MSIE 3.01 | ||
| 10 | =================================== | ||
| 11 | |||
| 12 | This document conatains all the information necessary to succesfully set up | ||
| 13 | some scripts to issue client certs to Microsoft Internet Explorer. It | ||
| 14 | includes the required knowledge about the model MSIE uses for client | ||
| 15 | certification and includes complete sample scripts ready to play with. The | ||
| 16 | scripts were tested against a modified ca program of SSLeay 0.6.6 and should | ||
| 17 | work with the regular ca program that comes with version 0.8.0. I haven't | ||
| 18 | tested against MSIE 4.0 | ||
| 19 | |||
| 20 | You can use the information contained in this document in either way you | ||
| 21 | want. However if you feel it saved you a lot of time I ask you to be as fair | ||
| 22 | as to mention my name: Holger Reif <reif@prakinf.tu-ilmenau.de>. | ||
| 23 | |||
| 24 | 1.) The model used by MSIE | ||
| 25 | -------------------------- | ||
| 26 | |||
| 27 | The Internet Explorer doesn't come with a embedded engine for installing | ||
| 28 | client certs like Netscape's Navigator. It rather uses the CryptoAPI (CAPI) | ||
| 29 | defined by Microsoft. CAPI comes with WindowsNT 4.0 or is installed together | ||
| 30 | with Internet Explorer since 3.01. The advantage of this approach is a higher | ||
| 31 | flexibility because the certificates in the (per user) system open | ||
| 32 | certificate store may be used by other applications as well. The drawback | ||
| 33 | however is that you need to do a bit more work to get a client cert issued. | ||
| 34 | |||
| 35 | CAPI defines functions which will handle basic cryptographic work, eg. | ||
| 36 | generating keys, encrypting some data, signing text or building a certificate | ||
| 37 | request. The procedure is as follows: A CAPI function generates you a key | ||
| 38 | pair and saves it into the certificate store. After that one builds a | ||
| 39 | Distinguished Name. Together with that key pair another CAPI function forms a | ||
| 40 | PKCS#10 request which you somehow need to submit to a CA. Finally the issued | ||
| 41 | cert is given to a yet another CAPI function which saves it into the | ||
| 42 | certificate store. | ||
| 43 | |||
| 44 | The certificate store with the user's keys and certs is in the registry. You | ||
| 45 | will find it under HKEY_CURRENT_USER/Software/Microsoft/Cryptography/ (I | ||
| 46 | leave it to you as a little exercise to figure out what all the entries mean | ||
| 47 | ;-). Note that the keys are protected only with the user's usual Windows | ||
| 48 | login password. | ||
| 49 | |||
| 50 | 2.) The practical usage | ||
| 51 | ----------------------- | ||
| 52 | |||
| 53 | Unfortunatly since CAPI is a system API you can't access its functions from | ||
| 54 | HTML code directly. For this purpose Microsoft provides a wrapper called | ||
| 55 | certenr3.dll. This DLL accesses the CAPI functions and provides an interface | ||
| 56 | usable from Visual Basic Script. One needs to install that library on the | ||
| 57 | computer which wants to have client cert. The easiest way is to load it as an | ||
| 58 | ActiveX control (certenr3.dll is properly authenticode signed by MS ;-). If | ||
| 59 | you have ever enrolled e cert request at a CA you will have installed it. | ||
| 60 | |||
| 61 | At time of writing certenr3.dll is contained in | ||
| 62 | http://www.microsoft.com/workshop/prog/security/csa/certenr3.exe. It comes | ||
| 63 | with an README file which explains the available functions. It is labeled | ||
| 64 | beta but every CA seems to use it anyway. The license.txt allows you the | ||
| 65 | usage for your own purposes (as far as I understood) and a somehow limited | ||
| 66 | distribution. | ||
| 67 | |||
| 68 | The two functions of main interest are GenerateKeyPair and AcceptCredentials. | ||
| 69 | For complete explanation of all possible parameters see the README file. Here | ||
| 70 | are only minimal required parameters and their values. | ||
| 71 | |||
| 72 | GenerateKeyPair(sessionID, FASLE, szName, 0, "ClientAuth", TRUE, FALSE, 1) | ||
| 73 | - sessionID is a (locally to that computer) unique string to correlate the | ||
| 74 | generated key pair with a cert installed later. | ||
| 75 | - szName is the DN of the form "C=DE; S=Thueringen; L=Ilmenau; CN=Holger | ||
| 76 | Reif; 1.2.840.113549.1.9.1=reif@prakinf.tu-ilmenau.de". Note that S is the | ||
| 77 | abreviation for StateOrProvince. The recognized abreviation include CN, O, C, | ||
| 78 | OU, G, I, L, S, T. If the abreviation is unknown (eg. for PKCS#9 email addr) | ||
| 79 | you need to use the full object identifier. The starting point for searching | ||
| 80 | them could be crypto/objects.h since all OIDs know to SSLeay are listed | ||
| 81 | there. | ||
| 82 | - note: the possible ninth parameter which should give a default name to the | ||
| 83 | certificate storage location doesn't seem to work. Changes to the constant | ||
| 84 | values in the call above doesn't seem to make sense. You can't generate | ||
| 85 | PKCS#10 extensions with that function. | ||
| 86 | |||
| 87 | The result of GenerateKeyPair is the base64 encoded PKCS#10 request. However | ||
| 88 | it has a little strange format that SSLeay doesn't accept. (BTW I feel the | ||
| 89 | decision of rejecting that format as standard conforming.) It looks like | ||
| 90 | follows: | ||
| 91 | 1st line with 76 chars | ||
| 92 | 2nd line with 76 chars | ||
| 93 | ... | ||
| 94 | (n-2)th line with 76 chars | ||
| 95 | (n-1)th line contains a multiple of 4 chars less then 76 (possible | ||
| 96 | empty) | ||
| 97 | (n)th line has zero or 4 chars (then with 1 or 2 equal signs - the | ||
| 98 | original text's lenght wasn'T a multiple of 3) | ||
| 99 | The line separator has two chars: 0x0d 0x0a | ||
| 100 | |||
| 101 | AcceptCredentials(sessionID, credentials, 0, FALSE) | ||
| 102 | - sessionID needs to be the same as while generating the key pair | ||
| 103 | - credentials is the base64 encoded PKCS#7 object containing the cert. | ||
| 104 | |||
| 105 | CRL's and CA certs are not required simply just the client cert. (It seems to | ||
| 106 | me that both are not even checked somehow.) The only format of the base64 | ||
| 107 | encoded object I succesfully used was all characters in a very long string | ||
| 108 | without line feeds or carriage returns. (Hey, it doesn't matter, only a | ||
| 109 | computer reads it!) | ||
| 110 | |||
| 111 | The result should be S_OK. For error handling see the example that comes with | ||
| 112 | certenr3.dll. | ||
| 113 | |||
| 114 | A note about ASN.1 character encodings. certenr3.dll seems to know only about | ||
| 115 | 2 of them: UniversalString and PrintableString. First it is definitely wrong | ||
| 116 | for an email address which is IA5STRING (checked by ssleay's ca). Second | ||
| 117 | unfortunately MSIE (at least until version 3.02) can't handle UniversalString | ||
| 118 | correctly - they just blow up you cert store! Therefore ssleay's ca (starting | ||
| 119 | from version 0.8.0) tries to convert the encodings automatically to IA5STRING | ||
| 120 | or TeletexString. The beef is it will work only for the latin-1 (western) | ||
| 121 | charset. Microsoft still has to do abit of homework... | ||
| 122 | |||
| 123 | 3.) An example | ||
| 124 | -------------- | ||
| 125 | |||
| 126 | At least you need two steps: generating the key & request and then installing | ||
| 127 | the certificate. A real world CA would have some more steps involved, eg. | ||
| 128 | accepting some license. Note that both scripts shown below are just | ||
| 129 | experimental state without any warrenty! | ||
| 130 | |||
| 131 | First how to generate a request. Note that we can't use a static page because | ||
| 132 | of the sessionID. I generate it from system time plus pid and hope it is | ||
| 133 | unique enough. Your are free to feed it through md5 to get more impressive | ||
| 134 | ID's ;-) Then the intended text is read in with sed which inserts the | ||
| 135 | sessionID. | ||
| 136 | |||
| 137 | -----BEGIN ms-enroll.cgi----- | ||
| 138 | #!/bin/sh | ||
| 139 | SESSION_ID=`date '+%y%m%d%H%M%S'`$$ | ||
| 140 | echo Content-type: text/html | ||
| 141 | echo | ||
| 142 | sed s/template_for_sessId/$SESSION_ID/ <<EOF | ||
| 143 | <HTML><HEAD> | ||
| 144 | <TITLE>Certificate Enrollment Test Page</TITLE> | ||
| 145 | </HEAD><BODY> | ||
| 146 | |||
| 147 | <OBJECT | ||
| 148 | classid="clsid:33BEC9E0-F78F-11cf-B782-00C04FD7BF43" | ||
| 149 | codebase=certenr3.dll | ||
| 150 | id=certHelper | ||
| 151 | > | ||
| 152 | </OBJECT> | ||
| 153 | |||
| 154 | <CENTER> | ||
| 155 | <H2>enrollment for a personal cert</H2> | ||
| 156 | <BR><HR WIDTH=50%><BR><P> | ||
| 157 | <FORM NAME="MSIE_Enrollment" ACTION="ms-gencert.cgi" ENCTYPE=x-www-form- | ||
| 158 | encoded METHOD=POST> | ||
| 159 | <TABLE> | ||
| 160 | <TR><TD>Country</TD><TD><INPUT NAME="Country" VALUE=""></TD></TR> | ||
| 161 | <TR><TD>State</TD><TD><INPUT NAME="StateOrProvince" VALUE=""></TD></TR> | ||
| 162 | <TR><TD>Location</TD><TD><INPUT NAME="Location" VALUE=""></TD></TR> | ||
| 163 | <TR><TD>Organization</TD><TD><INPUT NAME="Organization" | ||
| 164 | VALUE=""></TD></TR> | ||
| 165 | <TR><TD>Organizational Unit</TD> | ||
| 166 | <TD><INPUT NAME="OrganizationalUnit" VALUE=""></TD></TR> | ||
| 167 | <TR><TD>Name</TD><TD><INPUT NAME="CommonName" VALUE=""></TD></TR> | ||
| 168 | <TR><TD>eMail Address</TD> | ||
| 169 | <TD><INPUT NAME="EmailAddress" VALUE=""></TD></TR> | ||
| 170 | <TR><TD></TD> | ||
| 171 | <TD><INPUT TYPE="BUTTON" NAME="submit" VALUE="Beantragen"></TD></TR> | ||
| 172 | </TABLE> | ||
| 173 | <INPUT TYPE="hidden" NAME="SessionId" VALUE="template_for_sessId"> | ||
| 174 | <INPUT TYPE="hidden" NAME="Request" VALUE=""> | ||
| 175 | </FORM> | ||
| 176 | <BR><HR WIDTH=50%><BR><P> | ||
| 177 | </CENTER> | ||
| 178 | |||
| 179 | <SCRIPT LANGUAGE=VBS> | ||
| 180 | Dim DN | ||
| 181 | |||
| 182 | Sub Submit_OnClick | ||
| 183 | Dim TheForm | ||
| 184 | Set TheForm = Document.MSIE_Enrollment | ||
| 185 | sessionId = TheForm.SessionId.value | ||
| 186 | reqHardware = FALSE | ||
| 187 | C = TheForm.Country.value | ||
| 188 | SP = TheForm.StateOrProvince.value | ||
| 189 | L = TheForm.Location.value | ||
| 190 | O = TheForm.Organization.value | ||
| 191 | OU = TheForm.OrganizationalUnit.value | ||
| 192 | CN = TheForm.CommonName.value | ||
| 193 | Email = TheForm.EmailAddress.value | ||
| 194 | szPurpose = "ClientAuth" | ||
| 195 | doAcceptanceUINow = FALSE | ||
| 196 | doOnline = TRUE | ||
| 197 | |||
| 198 | DN = "" | ||
| 199 | |||
| 200 | Call Add_RDN("C", C) | ||
| 201 | Call Add_RDN("S", SP) | ||
| 202 | Call Add_RDN("L", L) | ||
| 203 | Call Add_RDN("O", O) | ||
| 204 | Call Add_RDN("OU", OU) | ||
| 205 | Call Add_RDN("CN", CN) | ||
| 206 | Call Add_RDN("1.2.840.113549.1.9.1", Email) | ||
| 207 | ' rsadsi | ||
| 208 | ' pkcs | ||
| 209 | ' pkcs9 | ||
| 210 | ' eMailAddress | ||
| 211 | On Error Resume Next | ||
| 212 | sz10 = certHelper.GenerateKeyPair(sessionId, _ | ||
| 213 | FALSE, DN, 0, ClientAuth, FASLE, TRUE, 1)_ | ||
| 214 | theError = Err.Number | ||
| 215 | On Error Goto 0 | ||
| 216 | if (sz10 = Empty OR theError <> 0) Then | ||
| 217 | sz = "The error '" & Hex(theError) & "' occurred." & chr(13) & _ | ||
| 218 | chr(10) & "Your credentials could not be generated." | ||
| 219 | result = MsgBox(sz, 0, "Credentials Enrollment") | ||
| 220 | Exit Sub | ||
| 221 | else | ||
| 222 | TheForm.Request.value = sz10 | ||
| 223 | TheForm.Submit | ||
| 224 | end if | ||
| 225 | End Sub | ||
| 226 | |||
| 227 | Sub Add_RDN(sn, value) | ||
| 228 | if (value <> "") then | ||
| 229 | if (DN <> "") then | ||
| 230 | DN = DN & "; " | ||
| 231 | end if | ||
| 232 | DN = DN & sn & "=" & value | ||
| 233 | end if | ||
| 234 | End Sub | ||
| 235 | </SCRIPT> | ||
| 236 | </BODY> | ||
| 237 | </HTML> | ||
| 238 | EOF | ||
| 239 | -----END ms-enroll.cgi----- | ||
| 240 | |||
| 241 | Second, how to extract the request and feed the certificate back? We need to | ||
| 242 | "normalize" the base64 encoding of the PKCS#10 format which means | ||
| 243 | regenerating the lines and wrapping with BEGIN and END line. This is done by | ||
| 244 | gawk. The request is taken by ca the normal way. Then the cert needs to be | ||
| 245 | packed into a PKCS#7 structure (note: the use of a CRL is necessary for | ||
| 246 | crl2pkcs7 as of version 0.6.6. Starting with 0.8.0 it it might probably be | ||
| 247 | ommited). Finally we need to format the PKCS#7 object and generate the HTML | ||
| 248 | text. I use two templates to have a clearer script. | ||
| 249 | |||
| 250 | 1st note: postit2 is slightly modified from a program I found at ncsa's ftp | ||
| 251 | site. Grab it from http://www.easterngraphics.com/certs/IX9704/postit2.c. You | ||
| 252 | need utils.c from there too. | ||
| 253 | |||
| 254 | 2nd note: I'm note quite sure wether the gawk script really handles all | ||
| 255 | possible inputs for the request right! Today I don't use this construction | ||
| 256 | anymore myself. | ||
| 257 | |||
| 258 | 3d note: the cert must be of version 3! This could be done with the nsComment | ||
| 259 | line in ssleay.cnf... | ||
| 260 | |||
| 261 | ------BEGIN ms-gencert.cgi----- | ||
| 262 | #!/bin/sh | ||
| 263 | FILE="/tmp/"`date '+%y%m%d%H%M%S'-`$$ | ||
| 264 | rm -f "$FILE".* | ||
| 265 | |||
| 266 | HOME=`pwd`; export HOME # as ssleay.cnf insists on having such an env var | ||
| 267 | cd /usr/local/ssl #where demoCA (as named in ssleay.conf) is located | ||
| 268 | |||
| 269 | postit2 -s " " -i 0x0d > "$FILE".inp # process the FORM vars | ||
| 270 | |||
| 271 | SESSION_ID=`gawk '$1 == "SessionId" { print $2; exit }' "$FILE".inp` | ||
| 272 | |||
| 273 | gawk \ | ||
| 274 | 'BEGIN { \ | ||
| 275 | OFS = ""; \ | ||
| 276 | print "-----BEGIN CERTIFICATE REQUEST-----"; \ | ||
| 277 | req_seen=0 \ | ||
| 278 | } \ | ||
| 279 | $1 == "Request" { \ | ||
| 280 | req_seen=1; \ | ||
| 281 | if (length($2) == 72) print($2); \ | ||
| 282 | lastline=$2; \ | ||
| 283 | next; \ | ||
| 284 | } \ | ||
| 285 | { \ | ||
| 286 | if (req_seen == 1) { \ | ||
| 287 | if (length($1) >= 72) print($1); \ | ||
| 288 | else if (length(lastline) < 72) { \ | ||
| 289 | req_seen=0; \ | ||
| 290 | print (lastline,$1); \ | ||
| 291 | } \ | ||
| 292 | lastline=$1; \ | ||
| 293 | } \ | ||
| 294 | } \ | ||
| 295 | END { \ | ||
| 296 | print "-----END CERTIFICATE REQUEST-----"; \ | ||
| 297 | }' > "$FILE".pem < "$FILE".inp | ||
| 298 | |||
| 299 | ssleay ca -batch -in "$FILE".pem -key passwd -out "$FILE".out | ||
| 300 | ssleay crl2pkcs7 -certfile "$FILE".out -out "$FILE".pkcs7 -in demoCA/crl.pem | ||
| 301 | |||
| 302 | sed s/template_for_sessId/$SESSION_ID/ <ms-enroll2a.html >"$FILE".cert | ||
| 303 | /usr/local/bin/gawk \ | ||
| 304 | 'BEGIN { \ | ||
| 305 | OFS = ""; \ | ||
| 306 | dq = sprintf("%c",34); \ | ||
| 307 | } \ | ||
| 308 | $0 ~ "PKCS7" { next; } \ | ||
| 309 | { \ | ||
| 310 | print dq$0dq" & _"; \ | ||
| 311 | }' <"$FILE".pkcs7 >> "$FILE".cert | ||
| 312 | cat ms-enroll2b.html >>"$FILE".cert | ||
| 313 | |||
| 314 | echo Content-type: text/html | ||
| 315 | echo Content-length: `wc -c "$FILE".cert` | ||
| 316 | echo | ||
| 317 | cat "$FILE".cert | ||
| 318 | rm -f "$FILE".* | ||
| 319 | -----END ms-gencert.cgi----- | ||
| 320 | |||
| 321 | ----BEGIN ms-enroll2a.html---- | ||
| 322 | <HTML><HEAD><TITLE>Certificate Acceptance Test Page</TITLE></HEAD><BODY> | ||
| 323 | |||
| 324 | <OBJECT | ||
| 325 | classid="clsid:33BEC9E0-F78F-11cf-B782-00C04FD7BF43" | ||
| 326 | codebase=certenr3.dll | ||
| 327 | id=certHelper | ||
| 328 | > | ||
| 329 | </OBJECT> | ||
| 330 | |||
| 331 | <CENTER> | ||
| 332 | <H2>Your personal certificate</H2> | ||
| 333 | <BR><HR WIDTH=50%><BR><P> | ||
| 334 | Press the button! | ||
| 335 | <P><INPUT TYPE=BUTTON VALUE="Nimm mich!" NAME="InstallCert"> | ||
| 336 | </CENTER> | ||
| 337 | <BR><HR WIDTH=50%><BR> | ||
| 338 | |||
| 339 | <SCRIPT LANGUAGE=VBS> | ||
| 340 | Sub InstallCert_OnClick | ||
| 341 | |||
| 342 | sessionId = "template_for_sessId" | ||
| 343 | credentials = "" & _ | ||
| 344 | ----END ms-enroll2a.html---- | ||
| 345 | |||
| 346 | ----BEGIN ms-enroll2b.html---- | ||
| 347 | "" | ||
| 348 | On Error Resume Next | ||
| 349 | result = certHelper.AcceptCredentials(sessionId, credentials, 0, | ||
| 350 | FALSE) | ||
| 351 | if (IsEmpty(result)) Then | ||
| 352 | sz = "The error '" & Err.Number & "' occurred." & chr(13) & | ||
| 353 | chr(10) & "This Digital ID could not be registered." | ||
| 354 | msgOut = MsgBox(sz, 0, "Credentials Registration Error") | ||
| 355 | navigate "error.html" | ||
| 356 | else | ||
| 357 | sz = "Digital ID successfully registered." | ||
| 358 | msgOut = MsgBox(sz, 0, "Credentials Registration") | ||
| 359 | navigate "success.html" | ||
| 360 | end if | ||
| 361 | Exit Sub | ||
| 362 | End Sub | ||
| 363 | </SCRIPT> | ||
| 364 | </BODY> | ||
| 365 | </HTML> | ||
| 366 | ----END ms-enroll2b.html---- | ||
| 367 | |||
| 368 | 4.) What do do with the cert? | ||
| 369 | ----------------------------- | ||
| 370 | |||
| 371 | The cert is visible (without restarting MSIE) under the following menu: | ||
| 372 | View->Options->Security->Personal certs. You can examine it's contents at | ||
| 373 | least partially. | ||
| 374 | |||
| 375 | To use it for client authentication you need to use SSL3.0 (fortunately | ||
| 376 | SSLeay supports it with 0.8.0). Furthermore MSIE is told to only supports a | ||
| 377 | kind of automatic selection of certs (I personally wasn't able to test it | ||
| 378 | myself). But there is a requirement that the issuer of the server cert and | ||
| 379 | the issuer of the client cert needs to be the same (according to a developer | ||
| 380 | from MS). Which means: you need may more then one cert to talk to all | ||
| 381 | servers... | ||
| 382 | |||
| 383 | I'm sure we will get a bit more experience after ApacheSSL is available for | ||
| 384 | SSLeay 0.8.8. | ||
| 385 | |||
| 386 | |||
| 387 | I hope you enjoyed reading and that in future questions on this topic will | ||
| 388 | rarely appear on ssl-users@moncom.com ;-) | ||
| 389 | |||
| 390 | Ilmenau, 9th of June 1997 | ||
| 391 | Holger Reif <reif@prakinf.tu-ilmenau.de> | ||
| 392 | -- | ||
| 393 | read you later - Holger Reif | ||
| 394 | ---------------------------------------- Signaturprojekt Deutsche Einheit | ||
| 395 | TU Ilmenau - Informatik - Telematik (Verdamp lang her) | ||
| 396 | Holger.Reif@PrakInf.TU-Ilmenau.DE Alt wie ein Baum werden, um ueber | ||
| 397 | http://Remus.PrakInf.TU-Ilmenau.DE/Reif/ alle 7 Bruecken gehen zu koennen | ||
| 398 | |||
