1SMIME TOOL (merged with ZXID.org project since 2009) 229.10.1999, 17.11.1999, Sampo Kellomaki <sampo@iki.fi> 3 4NOTE: This is still highly experimental code and build system has not been 5 perfected yet. No Windows build is known to exist (contributions?). 6 7OFFICIAL WEB SITE 8 http://zxid.org/Net_SSLeay/smime.html 9 10BUILDING 11 12 (build and install OpenSSL-0.9.4, from www.openssl.org) 13 tar xzf smime-0.7.tgz 14 cd smime-0.7 15 cons smime # get cons from http://www.dsmit.com/cons/ 16 cons SMIMEutil.so # build the perl module (optional) 17 ./smime -help # shows quick usage 18 ./smime -dv ../smime-0.7.tgz 19 (cut my certificate and distribution signature from the web 20 site and paste to stdin) 21 22TUTORIAL PART 1: SIGNING AND ENCRYPTING 23 24 First you need to have certicate and private key in pem format. To 25 produce them, use openssl tool or export them from your browser. 26 I illustrate the latter method first, because I'm going to use 27 Netscape browser for interoperability testing later. You can 28 peek at TUTORIAL PART3, Key generation if you need to do this 29 yourself. 30 31 - Go to security info dialog in Netscape browser. 32 - From Certificates-Yours export your certificate (if you 33 don't have a certificate installed yet, read the FAQs and mailing 34 list archieves at www.openssl.org), save it as me.p12. It 35 will ask for password to protect your private key. 36 37 openssl pkcs12 -clcerts <me.p12 >me.pem 38 - it will ask for the password to open your private key and 39 then asks you to invent a new password that will be 40 used to protect your private key in pem format 41 42 more me.pem 43 44 You should see something like this: 45 46Bag Attributes 47 friendlyName: your@email.com 48 localKeyID: F3 85 A8 4B DA 39 B6 40 6B D6 20 01 39 46 6A 94 47 9D 2C 0F 49Key Attributes: <No Attributes> 50-----BEGIN RSA PRIVATE KEY----- 51Proc-Type: 4,ENCRYPTED 52DEK-Info: DES-EDE3-CBC,541E04862A13F6B1 53 548+2vo6Iz49uj/Mf31JTgaRuIq9ueHsknsHXhmXp7s1BmS8xulT22Zzpdh6g1yqAO 55(snip)XeQsZrWykdWvN2qGu/cNa2HnUQAG0p25tNZ3CKmqpJBVg0RXr20JlQ== 56-----END RSA PRIVATE KEY----- 57Bag Attributes 58 friendlyName: your@email.com 59 localKeyID: F3 85 A8 4B DA 39 B6 40 6B D6 20 01 39 46 6A 94 47 9D 2C 0F 60subject=/C=PT/L=City/O=Company/OU=Dept/CN=Your Name/Email=your@email.com 61issuer= /C=PT/L=City/O=Your CA/OU=Personal Certs/CN=End user CA/Email=certifier@ca.com 62-----BEGIN CERTIFICATE----- 63MIIDEzCCAnygAwIBAgIBAzANBgkqhkiG9w0BAQQFADCBlTELMAkGA1UEBhMCUFQx 64(snip)Tj0JYGZMzSUfzOG3wajK6B39d6EyXK8= 65-----END CERTIFICATE----- 66 67 Ok. Now you are all set to use smime tool. First lets create 68 simple mime entity (see RFC1521 for definition): 69 70 echo foo | ./smime -mime text/plain | tee foo.mime 71 72Signing 73 Now, let's sign it: 74 75 ./smime -s me.pem password <foo.mime | tee foo.smime 76 77 And send it: 78 79 ./send.pl 'Sig test' your@email.com your@email.com <foo.smime 80 81 Now go to your email reading software (Netscape Communicator suggested 82 for this exercise) and read the mail you just sent. It should display 83 as signed. In the previous command the second argument is the 84 From: header which must match friendlyname/EMAIL in me.pem 85 86 You can repeat this success using following pipeline: 87 88 echo foo | ./smime -mime text/plain | ./smime -s me.pem password \ 89 | ./send.pl 'Sig test' your@email.com your@email.com 90 91 (Note how \ is used for folding the lines. In reality you should 92 type all the stuff in one line.) 93 94Clear signing 95 The previous method produces a base64 blob that you probaly would not 96 like to send to a news group. Clear signing allows mail to be read 97 even if the reader is not S/MIME aware: 98 99 echo foo | ./smime -mime text/plain | ./smime -cs me.pem password \ 100 | ./send.pl 'Sig test' your@email.com your@email.com 101 102 Note how the message has "foo" visible. Now go read this with your 103 mail reader. It should also display as signed. If not, then its 104 possible that canonization was not correctly done. That might even 105 be an error in my part. 106 107Encrypting 108 To encrypt you need to know recipient's cert. Here I use our own 109 because its by definition already installed in our browser. 110 111 echo foo | ./smime -mime text/plain | ./smime -e me.pem \ 112 | ./send.pl 'Enc test' your@email.com your@email.com 113 114 Now you should be able to read your mail (it may ask for a password 115 to open your private key) and see the message in plain text, but 116 marked as encrypted. 117 118Signing and Encrypting 119 Next we'll first sign a message and then wrap it in encryption. This 120 is the usual way and hides the signatories from eavesdroppers: 121 122 echo foo | ./smime -mime text/plain | ./smime -cs me.pem password \ 123 | ./smime -e me.pem | ./send.pl 'test' your@email.com your@email.com 124 125 Again your mail reader should show the message marked as 126 Encrypted and Signed. 127 128Encrypting and Signing 129 The other way is to first encrypt and then sign the encrypted 130 message. This might be useful in some automated context where a robot 131 would verify the signature but the robot should not be allowed to see 132 the message: 133 134 echo foo | ./smime -mime text/plain | ./smime -e me.pem \ 135 | ./smime -cs me.pem password \ 136 | ./send.pl 'Enc test' your@email.com your@email.com 137 138 Now Netscape shows two icons: one saying "Signed" and placed near 139 the headers. Other icon that says "Encrypted" appears in the 140 content area. 141 142 In fact S/MIME specification allows arbitrary nesting of encryptions 143 and signatures, what ever your application may need. 144 145Multipart content 146 Now for the final part that is not really S/MIME specific, but 147 nice to have. You can first compose a normal mime multipart message, 148 possibly even containing some encrypted components and some not. 149 Try this: 150 151 echo bar | ./smime -m image/gif some.gif \ 152 | ./smime -cs me.pem password | ./smime -e me.pem \ 153 | ./send.pl 'Enc test' your@email.com your@email.com 154 155 Now you should see signed and encrypted message with an image 156 attached. The multipart functionality implemented by -m is very 157 basic and by no means anything generic. Its only a demonstration. 158 159TUTORIAL PART 2: DECRYPTING AND VERIFYING SIGNATURES 160 161Decrypting 162 To demonstrate decrypting, I'll cut the mail from the loop. Basically 163 I'll demonstrate introperability with myself. If you want to try 164 interoperability with Netscape, you can use Netscape to send mail 165 and grab it from mail spool and then feed it into pipeline. As this 166 is a bit messy and might involve editing the file manually, I 167 wont go into that now. Here's a simple encryption - decryption: 168 169 echo foo | ./smime -mime text/plain | ./smime -e me.pem \ 170 | tee foo.p7m | ./smime -d me.pem passwd 171 172 foo wrapped in mime headers should come out. I also used tee(1) to 173 put the encrypted form in a file in case I also want to verify 174 it with Netscape 175 176 ./send.pl 'Enc test' your@email.com your@email.com <foo.p7m 177 178 or in qmail 179 180 /var/qmail/bin/qmail-inject your@email.com < foo.p7m 181 182 This is most convenient method because it allows you to import 183 certificates belonging to others than yourself and still 184 deliver mail to yourself. You want this, because you will soon 185 discover that Netscape can hold in its certificate database 186 only one certificate per email address (or is it distinguished name?) 187 and if that one "slot" is occupied, say, in "People" section, then 188 you can't import it any more to "Yours" section. Hence the solution 189 is to use different email address (and friendly name) every 190 single time. 191 192Verifying signature 193 Due to somewhat incomplete nature of OpenSSL-0.9.4 PKCS7 signature 194 verification code, I have implemented my own signature verfication 195 scheme that works in five steps 196 197 1. find out who signed the message 198 2. verify message signature using signer's certificate 199 3. find out who certified the signer's certificate 200 4. verify signer's cert using certifier's cert 201 5. repeat 3. & 4. until at root of the chain 202 203 This has the advantage that there are less obscure stuff and 204 assumptions hidden inside the program, i.e. user must understand 205 what signature and certificate verification is all about and 206 you get to observe every step of the way. The down side is that 207 its less automatic. In my particular application this does not 208 happen to be a problem because I have out of band information 209 about who is supposed to have signed what. 210 211 Here we go: lets produce a signature to play with 212 213 echo foo | ./smime -mime text/plain | tee foo.mime \ 214 | ./smime -s me.pem password | tee foo.p7m 215 216 Now see who signed it 217 218 ./smime -qs < foo.p7m 219 220 Now I assume that I have some way of finding the certificate using 221 the issuer DN and serial number returned in the previous step. These 222 two pieces of information constitute unique ID for a certificate. 223 Perhaps I keep my certs in LDAP or some other database. Anyway, 224 assume the certificate is found, then 225 226 ./smime -v me.pem <foo.p7m | tee foo2.mime 227 diff foo.mime foo2.mime # just to check! 228 229 Note that diff may show white space differences (try diff -b) because 230 line endings in your mime message were canonized to CRLF for signing. 231 This is mandated by S/MIME specification. 232 233 Now proceed with verifying the certificate: 234 235 ./smime -qc <me.pem 236 237 Now out of band means are used to find the signer's certificate. Then 238 to check that the signature matches: 239 240 ./smime -vc ca.pem <me.pem 241 242Verifying clear signature 243 (does not currently work :-( 244 245Under construction: chain verification (does not currently work) 246 mkdir certs 247 cd certs 248 cp ../me.pem . 249 ../hash-certs.pl *.pem 250 cd .. 251 echo foo | ./smime -mime text/plain | ./smime -s me.pem password \ 252 | ./smime -v 253 254TUTORIAL PART 3: A KEY GENERATION METHOD 255 256Bootstrapping a simple public key infrastructure 257 258 Suppose entity M is funding projects and needs to have all project 259 leaders (Ps) sign a contract specifying responsibilities. M 260 distributes a simple application that incorporates the smime tool. Ps 261 use the application to sign the contracts and send them electronically 262 to M. If irregularities develop, M sues P to court and uses the 263 digitally signed contract as evidence. For this to work 264 265 I. M must convince the court that the system does not have 266 technical flaws that could work in his favor. This proof 267 is much easier with digital signatures than with systems 268 that depend on procedural integrity (e.g. passwords over 269 SSL protected connection may prove at the moment the 270 intention of P, but when document is recovered from backup 271 10 years later, all procedural proofs vanish) 272 273 II. P's signature must be as valid as paper and ink 274 1. P's real world identity must be connected to 275 digital signature 276 2. P must have understood what it means to sign 277 contract digitally 278 3. P must have sufficient integrity or the system 279 must technically guarantee that P's private 280 key could not have been used by any one else 281 4. P must have acted by free will and in full powers 282 of mind 283 5. law must not prohibit digital signature 284 285 M needs to establish a simple public key infrastructure. I propose 286 that the application generates key pairs for P's and sends 287 certification requests, further, it also prints the certification 288 request in paper form including, 289 290 - fingerprint of public key (as number and as bar code) 291 - full dump of public key and all attributes appearing 292 in the certification request 293 - legal language to guarantee 2. & 3. (on point 3 we rely 294 on integrity) 295 - details of conventional identification of P 296 - space for signature 297 298 With this paper P goes to some commonly agreed and trustworthy 299 notary. This could be notary public or it could be some trusted 300 administrative organ in P's organization. It could even be M, but 301 that would cause a bureaucracy bottle neck at M, and hence increase 302 costs of the solution. 303 304 P signs the paper and proves his identity in presence of the notary 305 who confirms the act. The paper is sent to M. This takes care of 306 1. and 4. As paper contract about use of digital signatures now 307 exists between M and P, 5. is only of concern if it explicitly 308 nullifies such contract (or if court practice still does not consider 309 digital signature valid?). 310 311 Finally paper arrives to M where a clerk processes it (the bar 312 code helps here). He finds the certification request from data base 313 and sees that it matches the paper and issues a digital cerificate 314 that is immediately placed on a public server for everybody to 315 see. The paper is securely archieved forever. 316 317 Once the certificate is publically available, signing and verifying 318 contracts using it is trivial and can even be done between P and 319 some other party than M (e.g. certificate could be used for email). 320 321 However, to bootstrap the system it should, ideally, be possible 322 to sign your first contract even without waiting for the 323 certification to happen. After all, the impulse for P to adhere 324 to PKI of M came from needing to sign a contract (dead line for 325 research proposals may be very close). The contract would be 326 in signed, but not verified status until the certification happens. 327 328 Here the OpenSSL (or PKCS7?) does not serve us well, because it needs 329 a certificate even for the signing operation, although common 330 sense says that the private key and attributes of certification 331 request (ok, you can't know what serial number will be assigned) 332 should be enough. I solve this problem by signing the first contract 333 with a self signed certificate. Although this is quite suboptimal, 334 it allows me to get going without hacking OpenSSL innards too much. 335 Only complication arises from needing to establish that also the 336 certified public key is able to decrypt the hash of the signed 337 material. 338 339Key generation 340 341 Smime tool contains simple key generation command that will 342 make certification request as well as self signed cert. This 343 is bit simplistic and really geared towards my particular application 344 as the X509v3 certificate options are hardwired. Be sure to read 345 the source code to check they are the way you want. 346 347 echo "commonName=Joe Smith|emailAddress=joe@test.com" \ 348 | ./smime -kg "description=foo" passwd req.pem >priv_ss.pem 349 350 The stuff that is echoed to stdin is your distinguished name. You 351 must use long forms of attribute name and you can only use attributes 352 known to OpenSSL. 353 354 *** How to specify cn as needed by SSL certs? 355 356 The req.pem should be sent to certification authority for signing. 357 Meanwhile you can use the self signed certificate which was output 358 to stdout, here priv_ss.pem. Note that the private key is also 359 output to the stdout so do not give that file to anyone. If you need 360 to give the certificate, you should edit a copy of priv_ss.pem 361 and remove the private key. 362 363 To be able to import your private key and certificate to Netscape 364 you can use 365 366 ./smime -pem-p12 you@test.com passwd pw-for-p12 <priv_ss.pem >me.p12 367 368 The first argument (the email address) is the friendly name. Netscape 369 appears to match this against From mail header when verifying 370 signatures. For minimum troubles you should keep this equal to 371 emailAddress field of your certificate. 372 373Being a certificate authority 374 375 Once you have made your req.pem, you can send it to some commercial 376 certification authority or you can just be your own. The CA 377 functionality of smime tool is not very complete. Basically 378 it allows you to do the crypto part (signing certificate request with 379 CA's private key) but you must manually do book keeping to ensure 380 uniqueness of serial numbers and to make sure you do not issue the 381 same certificate twice, etc. 382 383 Here's how you'd sign a request (you probably used -kg to make 384 the CA's certificate): 385 386 ./smime -ca ca-id.pem very-secret 1 <req.pem >cert.pem 387 388 The number one is the serial number. As I said, you should do 389 bookkeeping to ensure you never reuse a serial number. Many 390 systems depend on being uniquely able to identify certificate 391 by its issuing authority and serial number. A certificate 392 authority that can not guarantee uniqueness of serial numbers is 393 not trustworthy. 394 395 Please note that the -ca hard wires all X509v3 options and extensions. 396 Be sure to read the source to check they are the way you want them. 397 398TUTORIAL PART 4: SIGNING AND VERIFYING SOFTWARE DISTRIBUTIONS 399 400 smime tool has detached signature feature which is meant for 401 signing and verifying software distributions. Here's how. First 402 make yourself an identity 403 404 echo 'commonName=my dist key|emailAddress=you@test.com' \ 405 | ./smime -kg '' pw dist-req.pem >dist-id.pem 406 407 Now open dist-id.pem in editor and save the certificate part as 408 dist-cert.pem. Pubish dist-cert.pem on your web site. 409 410 Then sign your software package 411 412 ./smime -ds dist-id.pem pw <your-dist-1.00.tgz >your-dist-1.00.sig 413 414 I suggest convention of naming the signature file with same name 415 as the tarball, but extension `.sig'. Now put the .sig file 416 available where ever you put your tarball. You should also publish 417 it on your web site so people can get it even if they forgot to 418 download the .sig file. 419 420 Or you could produce a combination signature and certificate file 421 and put that available on your website 422 423 ./smime -ds dist-id.pem pw <your-dist-1.00.tgz \ 424 | cat - dist-cert.pem >your-dist-1.00.sigcert 425 426 To verify a distribution signature one would say 427 428 ./smime -dv your-dist-1.00.tgz 429 (cut certificate and distribution signature from the web 430 site and paste to stdin) 431 432 The dv looks for the -----BEGIN/END CERTIFICATE----- separator to 433 figure out where the certificate ends and signature starts. 434 435 If you already had the .sig or the certificate you could just say 436 437 cat dist-cert.pem your-dist-1.00.sig | ./smime -dv your-dist-1.00.tgz 438 439 (OK, PGP already exists to do this stuff, but I always found it 440 quite messy to deal with detached signatures in PGP. I'm sure 441 poor usability leads to less people verifying the signatures.) 442 443SMIMEUTIL LIBRARY AND PERL MODULE 444 445 The smimeutil library is documented in smimeutil.h, see smime.c 446 for some examples of usage. The SMIMEUtil:: perl module is 447 not currently documented. For usage examples see test.pl. 448 449CAVEATS 450 For signing to work correctly, your mime entity must be canonized 451 the same way as the recipient will canonize it. In general this 452 means that you must use CRLF as line termination and must include 453 all headers. 454 455 If you are clear signing, then you may want to consult RFC2311 for 456 some ways the message might get ruined (e.g. changes in whitespace). 457 In my experience most important requirement seems to be to not 458 use any trailing whitespace. YMMV. 459 460 For signatures to verify correctly, the From: header of the mail 461 must be equal to "friendlyname:" and EMAIL fields in your cert. 462 463 When encrypting, do not forget to wrap your message in mime entity. 464 If you don't, ./smime -d will silently return emptiness, Netscape 465 reports "improperly formatted DER-encoded message". This 466 will _not_ work: 467 468 echo "foo" | ./smime -e me.pem | ./smime -d me.pem secret # WRONG! 469 470SECURITY CAVEATS 471 Passing passwords on command line is insecure. The smime tool is 472 intended more as a demonstration than a production tool. See 473 pass-password.pl for an example how to use file descriptor to 474 pass the passwords more securely. 475 476 smimeutil.c compiles by default to use DES-EDE3-CBC cipher which 477 is not known by export versions of many browsers. See around 478 line 400 in smime-enc.c if you need to change this. Be ware that 479 RC2-40-CBC can be cracked in real time by trivial resources. 480 Never-the-less its the only cipher that interoperates with all 481 versions of browsers. 482 483 Randomnumbers are not (yet) initialized as they should. 484 485 Certificate verification scheme puts the burden of verification 486 on user. For example, the user must notice if purported CA certificate 487 has X509v3 attribute that forbids it from being CA cert. 488 489TIP 490 You can use Netscape to encrypt and sign messages and then look 491 at them in mail spool. This way you see their raw structure before 492 any mail reader gets to interpret it. This is the best way to 493 debug differences between what you produce and what is presumably 494 standards compatible. 495 496TO DO 497 Parsing mime messages in robust and fully correct way 498 499BUGS 500 Due to the way the API is defined all stuff is kept in memory. While 501 this is simple and easy, you might get into trouble with large files. 502 I'd say the memory consumption will not exceed five times the file 503 size, but don't bet on it. 504 505 Signature verification in perl module still needs some work. 506 507SEE ALSO 508 RFC1521 (MIME) 509 RFC2111 (S/MIME v2) 510 *** RFCXXXX (S/MIME v3) 511 http://www.openssl.org 512 http://zxid.org/Net_SSLeay/smime.html (this stuff) 513 514USAGE 515 (reproduced from ./smime -help) 516 517 ./smime -cs private password <mime-entity >smime # clear sign 518 ./smime -cv cert <smime-entity >data # verify clear sig 519 ./smime -ds private passwd <file >smime-sig # make detached sig 520 ./smime -dv file <smime-sig-entity # verify detached 521 ./smime -s private password <mime-entity >smime # sign 522 ./smime -qs <smime-entity >signing-cert-info # find out who signed 523 ./smime -v cert <smime-entity >signer-dn # verify signature 524 525 ./smime -vc cacert <cert # verify certificate 526 527 ./smime -e public <mime-entity >smime-ent # encrypt 528 ./smime -d private password <smime-entity >mime # decrypt 529 530 ./smime -qr <req.pem # Query all you can about request 531 ./smime -qc <cert.pem # Query all you can about certificate 532 ./smime -ca ca_cert passwd serial <req.pem >cert.pem # sign a req 533 534 ./smime -p12-pem p12pw pempw <x.p12 >x.pem # convert PKCS12 to pem 535 ./smime -pem-p12 frindly@name.com pempw p12pw <x.pem >x.p12 536 537 ./smime -m type1 file1 type2 file2 type3 file3 <text # make multipart 538 ./smime -m image/gif foo.gif <message | ./smime -s private pass >smime 539 540 ./smime -kg attr passwd req.pem <dn >priv_ss.pem # keygen 541 542 ./smime -base64 <file >file.base64 543 ./smime -unbase64 <file.base64 >file 544 ./smime -mime text/plain <file >mime-entity 545 ./smime -mime_base64 image/gif <file.gif >mime-entity 546 ./smime -split dirprefix <multipart # splits multipart 547 ./smime -base64 <in | ./smime -unbase64 >out 548 ./smime -cat <in >out # copy input to output using slurp and barf 549 550 ./smime -kg 'description=Test' secret req.pem <me.dn >ss.pem 551 552--Sampo 553