Newer
Older
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
Bundle of old SSLeay documentation files [OBSOLETE!]
*** WARNING! WARNING! WARNING! WARNING! WARNING! WARNING! WARNING! ***
OBSOLETE means that nothing in this document should be trusted. This
document is provided mostly for historical purposes (it wasn't even up
to date at the time SSLeay 0.8.1 was released) and as inspiration. If
you copy some snippet of code from this document, please _check_ that
it really is correct from all points of view. For example, you can
check with the other documents in this directory tree, or by comparing
with relevant parts of the include files.
People have done the mistake of trusting what's written here. Please
don't do that.
*** WARNING! WARNING! WARNING! WARNING! WARNING! WARNING! WARNING! ***
==== readme ========================================================
This is the old 0.6.6 docuementation. Most of the cipher stuff is still
relevent but I'm working (very slowly) on new documentation.
The current version can be found online at
http://www.cryptsoft.com/ssleay/doc
==== API.doc ========================================================
SSL - SSLv2/v3/v23 etc.
BIO - methods and how they plug together
MEM - memory allocation callback
CRYPTO - locking for threads
EVP - Ciphers/Digests/signatures
RSA - methods
X509 - certificate retrieval
X509 - validation
X509 - X509v3 extensions
Objects - adding object identifiers
ASN.1 - parsing
PEM - parsing
==== ssl/readme =====================================================
22 Jun 1996
This file belongs in ../apps, but I'll leave it here because it deals
with SSL :-) It is rather dated but it gives you an idea of how
things work.
===
17 Jul 1995
I have been changing things quite a bit and have not fully updated
this file, so take what you read with a grain of salt
eric
===
The s_client and s_server programs can be used to test SSL capable
IP/port addresses and the verification of the X509 certificates in use
by these services. I strongly advise having a look at the code to get
an idea of how to use the authentication under SSLeay. Any feedback
on changes and improvements would be greatly accepted.
This file will probably be gibberish unless you have read
rfc1421, rfc1422, rfc1423 and rfc1424 which describe PEM
authentication.
A Brief outline (and examples) how to use them to do so.
NOTE:
The environment variable SSL_CIPER is used to specify the prefered
cipher to use, play around with setting it's value to combinations of
RC4-MD5, EXP-RC4-MD5, CBC-DES-MD5, CBC3-DES-MD5, CFB-DES-NULL
in a : separated list.
This directory contains 3 X509 certificates which can be used by these programs.
client.pem: a file containing a certificate and private key to be used
by s_client.
server.pem :a file containing a certificate and private key to be used
by s_server.
eay1024.pem:the certificate used to sign client.pem and server.pem.
This would be your CA's certificate. There is also a link
from the file a8556381.0 to eay1024.PEM. The value a8556381
is returned by 'x509 -hash -noout <eay1024.pem' and is the
value used by X509 verification routines to 'find' this
certificte when search a directory for it.
[the above is not true any more, the CA cert is
../certs/testca.pem which is signed by ../certs/mincomca.pem]
When testing the s_server, you may get
bind: Address already in use
errors. These indicate the port is still being held by the unix
kernel and you are going to have to wait for it to let go of it. If
this is the case, remember to use the port commands on the s_server and
s_client to talk on an alternative port.
=====
s_client.
This program can be used to connect to any IP/hostname:port that is
talking SSL. Once connected, it will attempt to authenticate the
certificate it was passed and if everything works as expected, a 2
directional channel will be open. Any text typed will be sent to the
other end. type Q<cr> to exit. Flags are as follows.
-host arg : Arg is the host or IP address to connect to.
-port arg : Arg is the port to connect to (https is 443).
-verify arg : Turn on authentication of the server certificate.
: Arg specifies the 'depth', this will covered below.
-cert arg : The optional certificate to use. This certificate
: will be returned to the server if the server
: requests it for client authentication.
-key arg : The private key that matches the certificate
: specified by the -cert option. If this is not
: specified (but -cert is), the -cert file will be
: searched for the Private key. Both files are
: assumed to be in PEM format.
-CApath arg : When to look for certificates when 'verifying' the
: certificate from the server.
-CAfile arg : A file containing certificates to be used for
: 'verifying' the server certificate.
-reconnect : Once a connection has been made, drop it and
: reconnect with same session-id. This is for testing :-).
The '-verify n' parameter specifies not only to verify the servers
certificate but to also only take notice of 'n' levels. The best way
to explain is to show via examples.
Given
s_server -cert server.PEM is running.
s_client
CONNECTED
depth=0 /C=AU/SOP=QLD/O=Mincom Pty. Ltd./OU=CS/CN=SSLeay demo server
issuer= /C=AU/SOP=QLD/O=Mincom Pty. Ltd./OU=CS/CN=CA
verify error:num=1:unable to get issuer certificate
verify return:1
CIPHER is CBC-DES-MD5
What has happened is that the 'SSLeay demo server' certificate's
issuer ('CA') could not be found but because verify is not on, we
don't care and the connection has been made anyway. It is now 'up'
using CBC-DES-MD5 mode. This is an unauthenticate secure channel.
You may not be talking to the right person but the data going to them
is encrypted.
s_client -verify 0
CONNECTED
depth=0 /C=AU/SOP=QLD/O=Mincom Pty. Ltd./OU=CS/CN=SSLeay demo server
issuer= /C=AU/SOP=QLD/O=Mincom Pty. Ltd./OU=CS/CN=CA
verify error:num=1:unable to get issuer certificate
verify return:1
CIPHER is CBC-DES-MD5
We are 'verifying' but only to depth 0, so since the 'SSLeay demo server'
certificate passed the date and checksum, we are happy to proceed.
s_client -verify 1
CONNECTED
depth=0 /C=AU/SOP=QLD/O=Mincom Pty. Ltd./OU=CS/CN=SSLeay demo server
issuer= /C=AU/SOP=QLD/O=Mincom Pty. Ltd./OU=CS/CN=CA
verify error:num=1:unable to get issuer certificate
verify return:0
ERROR
verify error:unable to get issuer certificate
In this case we failed to make the connection because we could not
authenticate the certificate because we could not find the
'CA' certificate.
s_client -verify 1 -CAfile eay1024.PEM
CONNECTED
depth=0 /C=AU/SOP=QLD/O=Mincom Pty. Ltd./OU=CS/CN=SSLeay demo server
verify return:1
depth=1 /C=AU/SOP=QLD/O=Mincom Pty. Ltd./OU=CS/CN=CA
verify return:1
CIPHER is CBC-DES-MD5
We loaded the certificates from the file eay1024.PEM. Everything
checked out and so we made the connection.
s_client -verify 1 -CApath .
CONNECTED
depth=0 /C=AU/SOP=QLD/O=Mincom Pty. Ltd./OU=CS/CN=SSLeay demo server
verify return:1
depth=1 /C=AU/SOP=QLD/O=Mincom Pty. Ltd./OU=CS/CN=CA
verify return:1
CIPHER is CBC-DES-MD5
We looked in out local directory for issuer certificates and 'found'
a8556381.0 and so everything is ok.
It is worth noting that 'CA' is a self certified certificate. If you
are passed one of these, it will fail to 'verify' at depth 0 because
we need to lookup the certifier of a certificate from some information
that we trust and keep locally.
SSL_CIPHER=CBC3-DES-MD5:RC4-MD5
export SSL_CIPHER
s_client -verify 10 -CApath . -reconnect
CONNECTED
depth=0 /C=AU/SOP=QLD/O=Mincom Pty. Ltd./OU=CS/CN=SSLeay demo server
verify return:1
depth=1 /C=AU/SOP=QLD/O=Mincom Pty. Ltd./OU=CS/CN=CA
verify return:1
drop the connection and reconnect with the same session id
CIPHER is CBC3-DES-MD5
This has done a full connection and then re-estabished it with the
same session id but a new socket. No RSA stuff occures on the second
connection. Note that we said we would prefer to use CBC3-DES-MD5
encryption and so, since the server supports it, we are.
=====
s_server
This program accepts SSL connections on a specified port
Once connected, it will estabish an SSL connection and optionaly
attempt to authenticate the client. A 2 directional channel will be
open. Any text typed will be sent to the other end. Type Q<cr> to exit.
Flags are as follows.
-port arg : Arg is the port to listen on.
-verify arg : Turn on authentication of the client if they have a
: certificate. Arg specifies the 'depth'.
-Verify arg : Turn on authentication of the client. If they don't
: have a valid certificate, drop the connection.
-cert arg : The certificate to use. This certificate
: will be passed to the client. If it is not
: specified, it will default to server.PEM
-key arg : The private key that matches the certificate
: specified by the -cert option. If this is not
: specified (but -cert is), the -cert file will be
: searched for the Private key. Both files are
: assumed to be in PEM format. Default is server.PEM
-CApath arg : When to look for certificates when 'verifying' the
: certificate from the client.
-CAfile arg : A file containing certificates to be used for
: 'verifying' the client certificate.
For the following 'demo' I will specify the s_server command and
the s_client command and then list the output from the s_server.
s_server
s_client
CONNECTED
CIPHER is CBC-DES-MD5
Everything up and running
s_server -verify 0
s_client
CONNECTED
CIPHER is CBC-DES-MD5
Ok since no certificate was returned and we don't care.
s_server -verify 0
./s_client -cert client.PEM
CONNECTED
depth=0 /C=AU/SOP=QLD/O=Mincom Pty. Ltd./OU=CS/CN=SSLeay demo client
issuer= /C=AU/SOP=QLD/O=Mincom Pty. Ltd./OU=CS/CN=CA
verify error:num=1:unable to get issuer certificate
verify return:1
CIPHER is CBC-DES-MD5
Ok since we were only verifying to level 0
s_server -verify 4
s_client -cert client.PEM
CONNECTED
depth=0 /C=AU/SOP=QLD/O=Mincom Pty. Ltd./OU=CS/CN=SSLeay demo client
issuer= /C=AU/SOP=QLD/O=Mincom Pty. Ltd./OU=CS/CN=CA
verify error:num=1:unable to get issuer certificate
verify return:0
ERROR
verify error:unable to get issuer certificate
Bad because we could not authenticate the returned certificate.
s_server -verify 4 -CApath .
s_client -cert client.PEM
CONNECTED
depth=0 /C=AU/SOP=QLD/O=Mincom Pty. Ltd./OU=CS/CN=SSLeay demo client
verify return:1
depth=1 /C=AU/SOP=QLD/O=Mincom Pty. Ltd./OU=CS/CN=CA
verify return:1
CIPHER is CBC-DES-MD5
Ok because we could authenticate the returned certificate :-).
s_server -Verify 0 -CApath .
s_client
CONNECTED
ERROR
SSL error:function is:REQUEST_CERTIFICATE
:error is :client end did not return a certificate
Error because no certificate returned.
s_server -Verify 4 -CApath .
s_client -cert client.PEM
CONNECTED
depth=0 /C=AU/SOP=QLD/O=Mincom Pty. Ltd./OU=CS/CN=SSLeay demo client
verify return:1
depth=1 /C=AU/SOP=QLD/O=Mincom Pty. Ltd./OU=CS/CN=CA
verify return:1
CIPHER is CBC-DES-MD5
Full authentication of the client.
So in summary to do full authentication of both ends
s_server -Verify 9 -CApath .
s_client -cert client.PEM -CApath . -verify 9
From the server side
CONNECTED
depth=0 /C=AU/SOP=QLD/O=Mincom Pty. Ltd./OU=CS/CN=SSLeay demo client
verify return:1
depth=1 /C=AU/SOP=QLD/O=Mincom Pty. Ltd./OU=CS/CN=CA
verify return:1
CIPHER is CBC-DES-MD5
From the client side
CONNECTED
depth=0 /C=AU/SOP=QLD/O=Mincom Pty. Ltd./OU=CS/CN=SSLeay demo server
verify return:1
depth=1 /C=AU/SOP=QLD/O=Mincom Pty. Ltd./OU=CS/CN=CA
verify return:1
CIPHER is CBC-DES-MD5
For general probing of the 'internet https' servers for the
distribution area, run
s_client -host www.netscape.com -port 443 -verify 4 -CApath ../rsa/hash
Then enter
GET /
and you should be talking to the https server on that host.
www.rsa.com was refusing to respond to connections on 443 when I was
testing.
have fun :-).
eric
==== a_verify.doc ========================================================
From eay@mincom.com Fri Oct 4 18:29:06 1996
Received: by orb.mincom.oz.au id AA29080
(5.65c/IDA-1.4.4 for eay); Fri, 4 Oct 1996 08:29:07 +1000
Date: Fri, 4 Oct 1996 08:29:06 +1000 (EST)
From: Eric Young <eay@mincom.oz.au>
X-Sender: eay@orb
To: wplatzer <wplatzer@iaik.tu-graz.ac.at>
Cc: Eric Young <eay@mincom.oz.au>, SSL Mailing List <ssl-users@mincom.com>
Subject: Re: Netscape's Public Key
In-Reply-To: <19961003134837.NTM0049@iaik.tu-graz.ac.at>
Message-Id: <Pine.SOL.3.91.961004081346.8018K-100000@orb>
Mime-Version: 1.0
Content-Type: TEXT/PLAIN; charset=US-ASCII
Status: RO
X-Status:
On Thu, 3 Oct 1996, wplatzer wrote:
> I get Public Key from Netscape (Gold 3.0b4), but cannot do anything
> with it... It looks like (asn1parse):
>
> 0:d=0 hl=3 l=180 cons: SEQUENCE
> 3:d=1 hl=2 l= 96 cons: SEQUENCE
> 5:d=2 hl=2 l= 92 cons: SEQUENCE
> 7:d=3 hl=2 l= 13 cons: SEQUENCE
> 9:d=4 hl=2 l= 9 prim: OBJECT :rsaEncryption
> 20:d=4 hl=2 l= 0 prim: NULL
> 22:d=3 hl=2 l= 75 prim: BIT STRING
> 99:d=2 hl=2 l= 0 prim: IA5STRING :
> 101:d=1 hl=2 l= 13 cons: SEQUENCE
> 103:d=2 hl=2 l= 9 prim: OBJECT :md5withRSAEncryption
> 114:d=2 hl=2 l= 0 prim: NULL
> 116:d=1 hl=2 l= 65 prim: BIT STRING
>
> The first BIT STRING is the public key and the second BIT STRING is
> the signature.
> But a public key consists of the public exponent and the modulus. Are
> both numbers in the first BIT STRING?
> Is there a document simply describing this coding stuff (checking
> signature, get the public key, etc.)?
Minimal in SSLeay. If you want to see what the modulus and exponent are,
try asn1parse -offset 25 -length 75 <key.pem
asn1parse will currently stuff up on the 'length 75' part (fixed in next
release) but it will print the stuff. If you are after more
documentation on ASN.1, have a look at www.rsa.com and get their PKCS
documents, most of my initial work on SSLeay was done using them.
As for SSLeay,
util/crypto.num and util/ssl.num are lists of all exported functions in
the library (but not macros :-(.
The ones for extracting public keys from certificates and certificate
requests are EVP_PKEY * X509_REQ_extract_key(X509_REQ *req);
EVP_PKEY * X509_extract_key(X509 *x509);
To verify a signature on a signed ASN.1 object
int X509_verify(X509 *a,EVP_PKEY *key);
int X509_REQ_verify(X509_REQ *a,EVP_PKEY *key);
int X509_CRL_verify(X509_CRL *a,EVP_PKEY *key);
int NETSCAPE_SPKI_verify(NETSCAPE_SPKI *a,EVP_PKEY *key);
I should mention that EVP_PKEY can be used to hold a public or a private key,
since for things like RSA and DSS, a public key is just a subset of what
is stored for the private key.
To sign any of the above structures
int X509_sign(X509 *a,EVP_PKEY *key,EVP_MD *md);
int X509_REQ_sign(X509_REQ *a,EVP_PKEY *key,EVP_MD *md);
int X509_CRL_sign(X509_CRL *a,EVP_PKEY *key,EVP_MD *md);
int NETSCAPE_SPKI_sign(NETSCAPE_SPKI *a,EVP_PKEY *key,EVP_MD *md);
where md is the message digest to sign with.
There are all defined in x509.h and all the _sign and _verify functions are
actually macros to the ASN1_sign() and ASN1_verify() functions.
These functions will put the correct algorithm identifiers in the correct
places in the structures.
eric
--
Eric Young | BOOL is tri-state according to Bill Gates.
AARNet: eay@mincom.oz.au | RTFM Win32 GetMessage().
==== x509 =======================================================
X509_verify()
X509_sign()
X509_get_version()
X509_get_serialNumber()
X509_get_issuer()
X509_get_subject()
X509_get_notBefore()
X509_get_notAfter()
X509_get_pubkey()
X509_set_version()
X509_set_serialNumber()
X509_set_issuer()
X509_set_subject()
X509_set_notBefore()
X509_set_notAfter()
X509_set_pubkey()
X509_get_extensions()
X509_set_extensions()
X509_EXTENSIONS_clear()
X509_EXTENSIONS_retrieve()
X509_EXTENSIONS_add()
X509_EXTENSIONS_delete()
==== x509 attribute ================================================
PKCS7
STACK of X509_ATTRIBUTES
ASN1_OBJECT
STACK of ASN1_TYPE
So it is
p7.xa[].obj
p7.xa[].data[]
get_obj_by_nid(STACK , nid)
get_num_by_nid(STACK , nid)
get_data_by_nid(STACK , nid, index)
X509_ATTRIBUTE *X509_ATTRIBUTE_new(void );
void X509_ATTRIBUTE_free(X509_ATTRIBUTE *a);
X509_ATTRIBUTE *X509_ATTRIBUTE_create_by_NID(X509_ATTRIBUTE **ex,
int nid, STACK *value);
X509_ATTRIBUTE *X509_ATTRIBUTE_create_by_OBJ(X509_ATTRIBUTE **ex,
int nid, STACK *value);
int X509_ATTRIBUTE_set_object(X509_ATTRIBUTE *ex,ASN1_OBJECT *obj);
int X509_ATTRIBUTE_add_data(X509_ATTRIBUTE *ex, int index,
ASN1_TYPE *value);
ASN1_OBJECT * X509_ATTRIBUTE_get_object(X509_ATTRIBUTE *ex);
int X509_ATTRIBUTE_get_num(X509_ATTRIBUTE *ne);
ASN1_TYPE * X509_ATTRIBUTE_get_data(X509_ATTRIBUTE *ne,int index);
ASN1_TYPE * X509_ATTRIBUTE_get_data_by_NID(X509_ATTRIBUTE *ne,
ASN1_OBJECT *obj);
X509_ATTRIBUTE *PKCS7_get_s_att_by_NID(PKCS7 *p7,int nid);
X509_ATTRIBUTE *PKCS7_get_u_att_by_NID(PKCS7 *p7,int nid);
==== x509 v3 ========================================================
The 'new' system.
The X509_EXTENSION_METHOD includes extensions and attributes and/or names.
Basically everthing that can be added to an X509 with an OID identifying it.
It operates via 2 methods per object id.
int a2i_XXX(X509 *x,char *str,int len);
int i2a_XXX(BIO *bp,X509 *x);
The a2i_XXX function will add the object with a value converted from the
string into the X509. Len can be -1 in which case the length is calculated
via strlen(str). Applications can always use direct knowledge to load and
unload the relevent objects themselves.
i2a_XXX will print to the passed BIO, a text representation of the
relevet object. Use a memory BIO if you want it printed to a buffer :-).
X509_add_by_NID(X509 *x,int nid,char *str,int len);
X509_add_by_OBJ(X509 *x,ASN1_OBJECT *obj,char *str,int len);
X509_print_by_name(BIO *bp,X509 *x);
X509_print_by_NID(BIO *bp,X509 *x);
X509_print_by_OBJ(BIO *bp,X509 *x);
==== verify ========================================================
X509_verify_cert_chain(
CERT_STORE *cert_store,
STACK /* X509 */ *certs,
int *verify_result,
int (*verify_error_callback)()
char *argument_to_callback, /* SSL */
app_verify_callback(
char *app_verify_arg, /* from SSL_CTX */
STACK /* X509 */ *certs,
int *verify_result,
int (*verify_error_callback)()
SSL *s,
int X509_verify_cert(
CERT_STORE *cert_store,
X509 *x509,
int *verify_result,
int (*verify_error_callback)(),
char *arg,
==== apps.doc ========================================================
The applications
Ok, where to begin....
In the begining, when SSLeay was small (April 1995), there
were but few applications, they did happily cohabit in
the one bin directory. Then over time, they did multiply and grow,
and they started to look like microsoft software; 500k to print 'hello world'.
A new approach was needed. They were coalessed into one 'Monolithic'
application, ssleay. This one program is composed of many programs that
can all be compiled independantly.
ssleay has 3 modes of operation.
1) If the ssleay binary has the name of one of its component programs, it
executes that program and then exits. This can be achieved by using hard or
symbolic links, or failing that, just renaming the binary.
2) If the first argument to ssleay is the name of one of the component
programs, that program runs that program and then exits.
3) If there are no arguments, ssleay enters a 'command' mode. Each line is
interpreted as a program name plus arguments. After each 'program' is run,
ssleay returns to the comand line.
dgst - message digests
enc - encryption and base64 encoding
ans1parse - 'pulls' appart ASN.1 encoded objects like certificates.
dh - Diffle-Hellman parameter manipulation.
rsa - RSA manipulations.
crl - Certificate revokion list manipulations
x509 - X509 cert fiddles, including signing.
pkcs7 - pkcs7 manipulation, only DER versions right now.
genrsa - generate an RSA private key.
gendh - Generate a set of Diffle-Hellman parameters.
req - Generate a PKCS#10 object, a certificate request.
s_client - SSL client program
s_server - SSL server program
s_time - A SSL protocol timing program
s_mult - Another SSL server, but it multiplexes
connections.
s_filter - under development
errstr - Convert SSLeay error numbers to strings.
ca - Sign certificate requests, and generate
certificate revokion lists
crl2pkcs7 - put a crl and certifcates into a pkcs7 object.
speed - Benchmark the ciphers.
verify - Check certificates
hashdir - under development
[ there a now a few more options, play with the program to see what they
are ]
==== asn1.doc ========================================================
The ASN.1 Routines.
ASN.1 is a specification for how to encode structured 'data' in binary form.
The approach I have take to the manipulation of structures and their encoding
into ASN.1 is as follows.
For each distinct structure there are 4 function of the following form
TYPE *TYPE_new(void);
void TYPE_free(TYPE *);
TYPE *d2i_TYPE(TYPE **a,unsigned char **pp,long length);
long i2d_TYPE(TYPE *a,unsigned char **pp); /* CHECK RETURN VALUE */
where TYPE is the type of the 'object'. The TYPE that have these functions
can be in one of 2 forms, either the internal C malloc()ed data structure
or in the DER (a variant of ASN.1 encoding) binary encoding which is just
an array of unsigned bytes. The 'i2d' functions converts from the internal
form to the DER form and the 'd2i' functions convert from the DER form to
the internal form.
The 'new' function returns a malloc()ed version of the structure with all
substructures either created or left as NULL pointers. For 'optional'
fields, they are normally left as NULL to indicate no value. For variable
size sub structures (often 'SET OF' or 'SEQUENCE OF' in ASN.1 syntax) the
STACK data type is used to hold the values. Have a read of stack.doc
and have a look at the relevant header files to see what I mean. If there
is an error while malloc()ing the structure, NULL is returned.
The 'free' function will free() all the sub components of a particular
structure. If any of those sub components have been 'removed', replace
them with NULL pointers, the 'free' functions are tolerant of NULL fields.
The 'd2i' function copies a binary representation into a C structure. It
operates as follows. 'a' is a pointer to a pointer to
the structure to populate, 'pp' is a pointer to a pointer to where the DER
byte string is located and 'length' is the length of the '*pp' data.
If there are no errors, a pointer to the populated structure is returned.
If there is an error, NULL is returned. Errors can occur because of
malloc() failures but normally they will be due to syntax errors in the DER
encoded data being parsed. It is also an error if there was an
attempt to read more that 'length' bytes from '*p'. If
everything works correctly, the value in '*p' is updated
to point at the location just beyond where the DER
structure was read from. In this way, chained calls to 'd2i' type
functions can be made, with the pointer into the 'data' array being
'walked' along the input byte array.
Depending on the value passed for 'a', different things will be done. If
'a' is NULL, a new structure will be malloc()ed and returned. If '*a' is
NULL, a new structure will be malloc()ed and put into '*a' and returned.
If '*a' is not NULL, the structure in '*a' will be populated, or in the
case of an error, free()ed and then returned.
Having these semantics means that a structure
can call a 'd2i' function to populate a field and if the field is currently
NULL, the structure will be created.
The 'i2d' function type is used to copy a C structure to a byte array.
The parameter 'a' is the structure to convert and '*p' is where to put it.
As for the 'd2i' type structure, 'p' is updated to point after the last
byte written. If p is NULL, no data is written. The function also returns
the number of bytes written. Where this becomes useful is that if the
function is called with a NULL 'p' value, the length is returned. This can
then be used to malloc() an array of bytes and then the same function can
be recalled passing the malloced array to be written to. e.g.
int len;
unsigned char *bytes,*p;
len=i2d_X509(x,NULL); /* get the size of the ASN1 encoding of 'x' */
if ((bytes=(unsigned char *)malloc(len)) == NULL)
goto err;
p=bytes;
i2d_X509(x,&p);
Please note that a new variable, 'p' was passed to i2d_X509. After the
call to i2d_X509 p has been incremented by len bytes.
Now the reason for this functional organisation is that it allows nested
structures to be built up by calling these functions as required. There
are various macros used to help write the general 'i2d', 'd2i', 'new' and
'free' functions. They are discussed in another file and would only be
used by some-one wanting to add new structures to the library. As you
might be able to guess, the process of writing ASN.1 files can be a bit CPU
expensive for complex structures. I'm willing to live with this since the
simpler library code make my life easier and hopefully most programs using
these routines will have their execution profiles dominated by cipher or
message digest routines.
What follows is a list of 'TYPE' values and the corresponding ASN.1
structure and where it is used.
TYPE ASN.1
ASN1_INTEGER INTEGER
ASN1_BIT_STRING BIT STRING
ASN1_OCTET_STRING OCTET STRING
ASN1_OBJECT OBJECT IDENTIFIER
ASN1_PRINTABLESTRING PrintableString
ASN1_T61STRING T61String
ASN1_IA5STRING IA5String
ASN1_UTCTIME UTCTime
ASN1_TYPE Any of the above mentioned types plus SEQUENCE and SET
Most of the above mentioned types are actualled stored in the
ASN1_BIT_STRING type and macros are used to differentiate between them.
The 3 types used are
typedef struct asn1_object_st
{
/* both null if a dynamic ASN1_OBJECT, one is
* defined if a 'static' ASN1_OBJECT */
char *sn,*ln;
int nid;
int length;
unsigned char *data;
} ASN1_OBJECT;
This is used to store ASN1 OBJECTS. Read 'objects.doc' for details ono
routines to manipulate this structure. 'sn' and 'ln' are used to hold text
strings that represent the object (short name and long or lower case name).
These are used by the 'OBJ' library. 'nid' is a number used by the OBJ
library to uniquely identify objects. The ASN1 routines will populate the
'length' and 'data' fields which will contain the bit string representing
the object.
typedef struct asn1_bit_string_st
{
int length;
int type;
unsigned char *data;
} ASN1_BIT_STRING;
This structure is used to hold all the other base ASN1 types except for
ASN1_UTCTIME (which is really just a 'char *'). Length is the number of
bytes held in data and type is the ASN1 type of the object (there is a list
in asn1.h).
typedef struct asn1_type_st
{
int type;
union {
char *ptr;
ASN1_INTEGER * integer;
ASN1_BIT_STRING * bit_string;
ASN1_OCTET_STRING * octet_string;
ASN1_OBJECT * object;
ASN1_PRINTABLESTRING * printablestring;
ASN1_T61STRING * t61string;
ASN1_IA5STRING * ia5string;
ASN1_UTCTIME * utctime;
ASN1_BIT_STRING * set;
ASN1_BIT_STRING * sequence;
} value;
} ASN1_TYPE;
This structure is used in a few places when 'any' type of object can be
expected.
X509 Certificate
X509_CINF CertificateInfo
X509_ALGOR AlgorithmIdentifier
X509_NAME Name
X509_NAME_ENTRY A single sub component of the name.
X509_VAL Validity
X509_PUBKEY SubjectPublicKeyInfo
The above mentioned types are declared in x509.h. They are all quite
straight forward except for the X509_NAME/X509_NAME_ENTRY pair.
A X509_NAME is a STACK (see stack.doc) of X509_NAME_ENTRY's.
typedef struct X509_name_entry_st
{
ASN1_OBJECT *object;
ASN1_BIT_STRING *value;
int set;
int size; /* temp variable */
} X509_NAME_ENTRY;
The size is a temporary variable used by i2d_NAME and set is the set number
for the particular NAME_ENTRY. A X509_NAME is encoded as a sequence of
sequence of sets. Normally each set contains only a single item.
Sometimes it contains more. Normally throughout this library there will be
only one item per set. The set field contains the 'set' that this entry is
a member of. So if you have just created a X509_NAME structure and
populated it with X509_NAME_ENTRYs, you should then traverse the X509_NAME
(which is just a STACK) and set the 'set/' field to incrementing numbers.
For more details on why this is done, read the ASN.1 spec for Distinguished
Names.
X509_REQ CertificateRequest
X509_REQ_INFO CertificateRequestInfo
These are used to hold certificate requests.
X509_CRL CertificateRevocationList
These are used to hold a certificate revocation list
RSAPrivateKey PrivateKeyInfo
RSAPublicKey PublicKeyInfo
Both these 'function groups' operate on 'RSA' structures (see rsa.doc).
The difference is that the RSAPublicKey operations only manipulate the m
and e fields in the RSA structure.
DSAPrivateKey DSS private key
DSAPublicKey DSS public key
Both these 'function groups' operate on 'DSS' structures (see dsa.doc).
The difference is that the RSAPublicKey operations only manipulate the
XXX fields in the DSA structure.
DHparams DHParameter
This is used to hold the p and g value for The Diffie-Hellman operation.
The function deal with the 'DH' strucure (see dh.doc).
Now all of these function types can be used with several other functions to give
quite useful set of general manipulation routines. Normally one would
not uses these functions directly but use them via macros.
char *ASN1_dup(int (*i2d)(),char *(*d2i)(),char *x);
'x' is the input structure case to a 'char *', 'i2d' is the 'i2d_TYPE'
function for the type that 'x' is and d2i is the 'd2i_TYPE' function for the
type that 'x' is. As is obvious from the parameters, this function
duplicates the strucutre by transforming it into the DER form and then
re-loading it into a new strucutre and returning the new strucutre. This
is obviously a bit cpu intensive but when faced with a complex dynamic
structure this is the simplest programming approach. There are macros for
duplicating the major data types but is simple to add extras.
char *ASN1_d2i_fp(char *(*new)(),char *(*d2i)(),FILE *fp,unsigned char **x);
'x' is a pointer to a pointer of the 'desired type'. new and d2i are the
corresponding 'TYPE_new' and 'd2i_TYPE' functions for the type and 'fp' is
an open file pointer to read from. This function reads from 'fp' as much
data as it can and then uses 'd2i' to parse the bytes to load and return
the parsed strucutre in 'x' (if it was non-NULL) and to actually return the
strucutre. The behavior of 'x' is as per all the other d2i functions.
char *ASN1_d2i_bio(char *(*new)(),char *(*d2i)(),BIO *fp,unsigned char **x);
The 'BIO' is the new IO type being used in SSLeay (see bio.doc). This
function is the same as ASN1_d2i_fp() except for the BIO argument.
ASN1_d2i_fp() actually calls this function.
int ASN1_i2d_fp(int (*i2d)(),FILE *out,unsigned char *x);
'x' is converted to bytes by 'i2d' and then written to 'out'. ASN1_i2d_fp
and ASN1_d2i_fp are not really symetric since ASN1_i2d_fp will read all
available data from the file pointer before parsing a single item while
ASN1_i2d_fp can be used to write a sequence of data objects. To read a
series of objects from a file I would sugest loading the file into a buffer
and calling the relevent 'd2i' functions.
char *ASN1_d2i_bio(char *(*new)(),char *(*d2i)(),BIO *fp,unsigned char **x);
This function is the same as ASN1_i2d_fp() except for the BIO argument.
ASN1_i2d_fp() actually calls this function.
char * PEM_ASN1_read(char *(*d2i)(),char *name,FILE *fp,char **x,int (*cb)());
This function will read the next PEM encoded (base64) object of the same
type as 'x' (loaded by the d2i function). 'name' is the name that is in
the '-----BEGIN name-----' that designates the start of that object type.
If the data is encrypted, 'cb' will be called to prompt for a password. If
it is NULL a default function will be used to prompt from the password.
'x' is delt with as per the standard 'd2i' function interface. This
function can be used to read a series of objects from a file. While any
data type can be encrypted (see PEM_ASN1_write) only RSA private keys tend
to be encrypted.
char * PEM_ASN1_read_bio(char *(*d2i)(),char *name,BIO *fp,
char **x,int (*cb)());
Same as PEM_ASN1_read() except using a BIO. This is called by
PEM_ASN1_read().
int PEM_ASN1_write(int (*i2d)(),char *name,FILE *fp,char *x,EVP_CIPHER *enc,
unsigned char *kstr,int klen,int (*callback)());
int PEM_ASN1_write_bio(int (*i2d)(),char *name,BIO *fp,
char *x,EVP_CIPHER *enc,unsigned char *kstr,int klen,
int (*callback)());
int ASN1_sign(int (*i2d)(), X509_ALGOR *algor1, X509_ALGOR *algor2,
ASN1_BIT_STRING *signature, char *data, RSA *rsa, EVP_MD *type);
int ASN1_verify(int (*i2d)(), X509_ALGOR *algor1,
ASN1_BIT_STRING *signature,char *data, RSA *rsa);
int ASN1_BIT_STRING_cmp(ASN1_BIT_STRING *a, ASN1_BIT_STRING *b);
ASN1_BIT_STRING *ASN1_BIT_STRING_type_new(int type );
int ASN1_UTCTIME_check(ASN1_UTCTIME *a);
void ASN1_UTCTIME_print(BIO *fp,ASN1_UTCTIME *a);
ASN1_UTCTIME *ASN1_UTCTIME_dup(ASN1_UTCTIME *a);
ASN1_BIT_STRING *d2i_asn1_print_type(ASN1_BIT_STRING **a,unsigned char **pp,
long length,int type);
int i2d_ASN1_SET(STACK *a, unsigned char **pp,
int (*func)(), int ex_tag, int ex_class);
STACK * d2i_ASN1_SET(STACK **a, unsigned char **pp, long length,
char *(*func)(), int ex_tag, int ex_class);
int i2a_ASN1_OBJECT(BIO *bp,ASN1_OBJECT *object);
int i2a_ASN1_INTEGER(BIO *bp, ASN1_INTEGER *a);
int a2i_ASN1_INTEGER(BIO *bp,ASN1_INTEGER *bs,char *buf,int size);
int ASN1_INTEGER_set(ASN1_INTEGER *a, long v);
long ASN1_INTEGER_get(ASN1_INTEGER *a);
ASN1_INTEGER *BN_to_ASN1_INTEGER(BIGNUM *bn, ASN1_INTEGER *ai);
BIGNUM *ASN1_INTEGER_to_BN(ASN1_INTEGER *ai,BIGNUM *bn);
/* given a string, return the correct type. Max is the maximum number
* of bytes to parse. It stops parsing when 'max' bytes have been
* processed or a '\0' is hit */
int ASN1_PRINTABLE_type(unsigned char *s,int max);
void ASN1_parse(BIO *fp,unsigned char *pp,long len);
int i2d_ASN1_bytes(ASN1_BIT_STRING *a, unsigned char **pp, int tag, int class);
ASN1_BIT_STRING *d2i_ASN1_bytes(ASN1_OCTET_STRING **a, unsigned char **pp,
long length, int Ptag, int Pclass);
/* PARSING */
int asn1_Finish(ASN1_CTX *c);
/* SPECIALS */
int ASN1_get_object(unsigned char **pp, long *plength, int *ptag,
int *pclass, long omax);
int ASN1_check_infinite_end(unsigned char **p,long len);
void ASN1_put_object(unsigned char **pp, int constructed, int length,
int tag, int class);
int ASN1_object_size(int constructed, int length, int tag);
X509 * X509_get_cert(CERTIFICATE_CTX *ctx,X509_NAME * name,X509 *tmp_x509);
int X509_add_cert(CERTIFICATE_CTX *ctx,X509 *);
char * X509_cert_verify_error_string(int n);
int X509_add_cert_file(CERTIFICATE_CTX *c,char *file, int type);
char * X509_gmtime (char *s, long adj);
int X509_add_cert_dir (CERTIFICATE_CTX *c,char *dir, int type);
int X509_load_verify_locations (CERTIFICATE_CTX *ctx,
char *file_env, char *dir_env);
int X509_set_default_verify_paths(CERTIFICATE_CTX *cts);
X509 * X509_new_D2i_X509(int len, unsigned char *p);
char * X509_get_default_cert_area(void );
char * X509_get_default_cert_dir(void );
char * X509_get_default_cert_file(void );
char * X509_get_default_cert_dir_env(void );
char * X509_get_default_cert_file_env(void );
char * X509_get_default_private_dir(void );
X509_REQ *X509_X509_TO_req(X509 *x, RSA *rsa);
int X509_cert_verify(CERTIFICATE_CTX *ctx,X509 *xs, int (*cb)());
CERTIFICATE_CTX *CERTIFICATE_CTX_new();
void CERTIFICATE_CTX_free(CERTIFICATE_CTX *c);
void X509_NAME_print(BIO *fp, X509_NAME *name, int obase);
int X509_print_fp(FILE *fp,X509 *x);
int X509_print(BIO *fp,X509 *x);
X509_INFO * X509_INFO_new(void);
void X509_INFO_free(X509_INFO *a);
char * X509_NAME_oneline(X509_NAME *a);
#define X509_verify(x,rsa)
#define X509_REQ_verify(x,rsa)
#define X509_CRL_verify(x,rsa)
#define X509_sign(x,rsa,md)
#define X509_REQ_sign(x,rsa,md)
#define X509_CRL_sign(x,rsa,md)
#define X509_dup(x509)
#define d2i_X509_fp(fp,x509)
#define i2d_X509_fp(fp,x509)
#define d2i_X509_bio(bp,x509)
#define i2d_X509_bio(bp,x509)
#define X509_CRL_dup(crl)
#define d2i_X509_CRL_fp(fp,crl)
#define i2d_X509_CRL_fp(fp,crl)
#define d2i_X509_CRL_bio(bp,crl)
#define i2d_X509_CRL_bio(bp,crl)
#define X509_REQ_dup(req)
#define d2i_X509_REQ_fp(fp,req)
#define i2d_X509_REQ_fp(fp,req)
#define d2i_X509_REQ_bio(bp,req)
#define i2d_X509_REQ_bio(bp,req)
#define RSAPrivateKey_dup(rsa)
#define d2i_RSAPrivateKey_fp(fp,rsa)
#define i2d_RSAPrivateKey_fp(fp,rsa)
#define d2i_RSAPrivateKey_bio(bp,rsa)
#define i2d_RSAPrivateKey_bio(bp,rsa)
#define X509_NAME_dup(xn)
#define X509_NAME_ENTRY_dup(ne)
void X509_REQ_print_fp(FILE *fp,X509_REQ *req);
void X509_REQ_print(BIO *fp,X509_REQ *req);
RSA *X509_REQ_extract_key(X509_REQ *req);
RSA *X509_extract_key(X509 *x509);
int X509_issuer_and_serial_cmp(X509 *a, X509 *b);
unsigned long X509_issuer_and_serial_hash(X509 *a);
X509_NAME * X509_get_issuer_name(X509 *a);
int X509_issuer_name_cmp(X509 *a, X509 *b);
unsigned long X509_issuer_name_hash(X509 *a);
X509_NAME * X509_get_subject_name(X509 *a);
int X509_subject_name_cmp(X509 *a,X509 *b);
unsigned long X509_subject_name_hash(X509 *x);
int X509_NAME_cmp (X509_NAME *a, X509_NAME *b);
unsigned long X509_NAME_hash(X509_NAME *x);
==== bio.doc ========================================================
BIO Routines