]> gitweb.factorcode.org Git - factor.git/blob - basis/io/sockets/secure/openssl/openssl.factor
Merge branch 'master' into experimental (untested!)
[factor.git] / basis / io / sockets / secure / openssl / openssl.factor
1 ! Copyright (C) 2007, 2008, Slava Pestov, Elie CHAFTARI.
2 ! See http://factorcode.org/license.txt for BSD license.
3 USING: accessors byte-arrays kernel sequences
4 namespaces math math.order combinators init alien alien.c-types
5 alien.strings libc continuations destructors summary
6 splitting assocs random math.parser locals unicode.case openssl
7 openssl.libcrypto openssl.libssl io.backend io.ports io.files
8 io.encodings.8-bit io.timeouts io.sockets.secure ;
9 IN: io.sockets.secure.openssl
10
11 GENERIC: ssl-method ( symbol -- method )
12
13 M: SSLv2  ssl-method drop SSLv2_client_method ;
14 M: SSLv23 ssl-method drop SSLv23_method ;
15 M: SSLv3  ssl-method drop SSLv3_method ;
16 M: TLSv1  ssl-method drop TLSv1_method ;
17
18 TUPLE: openssl-context < secure-context aliens sessions ;
19
20 : set-session-cache ( ctx -- )
21     handle>>
22     [ SSL_SESS_CACHE_BOTH SSL_CTX_set_session_cache_mode ssl-error ]
23     [ 32 random-bits >hex dup length SSL_CTX_set_session_id_context ssl-error ]
24     bi ;
25
26 : load-certificate-chain ( ctx -- )
27     dup config>> key-file>> [
28         [ handle>> ] [ config>> key-file>> (normalize-path) ] bi
29         SSL_CTX_use_certificate_chain_file
30         ssl-error
31     ] [ drop ] if ;
32
33 : password-callback ( -- alien )
34     "int" { "void*" "int" "bool" "void*" } "cdecl"
35     [| buf size rwflag password! |
36         password [ B{ 0 } password! ] unless
37
38         [let | len [ password strlen ] |
39             buf password len 1+ size min memcpy
40             len
41         ]
42     ] alien-callback ;
43
44 : default-pasword ( ctx -- alien )
45     [ config>> password>> latin1 malloc-string ] [ aliens>> ] bi
46     [ push ] [ drop ] 2bi ;
47
48 : set-default-password ( ctx -- )
49     [ handle>> password-callback SSL_CTX_set_default_passwd_cb ]
50     [
51         [ handle>> ] [ default-pasword ] bi
52         SSL_CTX_set_default_passwd_cb_userdata
53     ] bi ;
54
55 : use-private-key-file ( ctx -- )
56     dup config>> key-file>> [
57         [ handle>> ] [ config>> key-file>> (normalize-path) ] bi
58         SSL_FILETYPE_PEM SSL_CTX_use_PrivateKey_file
59         ssl-error
60     ] [ drop ] if ;
61
62 : load-verify-locations ( ctx -- )
63     dup config>> [ ca-file>> ] [ ca-path>> ] bi or [
64         [ handle>> ]
65         [
66             config>>
67             [ ca-file>> dup [ (normalize-path) ] when ]
68             [ ca-path>> dup [ (normalize-path) ] when ] bi
69         ] bi
70         SSL_CTX_load_verify_locations
71     ] [ handle>> SSL_CTX_set_default_verify_paths ] if ssl-error ;
72
73 : set-verify-depth ( ctx -- )
74     dup config>> verify-depth>> [
75         [ handle>> ] [ config>> verify-depth>> ] bi
76         SSL_CTX_set_verify_depth
77     ] [ drop ] if ;
78
79 TUPLE: bio handle disposed ;
80
81 : <bio> ( handle -- bio ) f bio boa ;
82
83 M: bio dispose* handle>> BIO_free ssl-error ;
84
85 : <file-bio> ( path -- bio )
86     normalize-path "r" BIO_new_file dup ssl-error <bio> ;
87
88 : load-dh-params ( ctx -- )
89     dup config>> dh-file>> [
90         [ handle>> ] [ config>> dh-file>> ] bi <file-bio> &dispose
91         handle>> f f f PEM_read_bio_DHparams dup ssl-error
92         SSL_CTX_set_tmp_dh ssl-error
93     ] [ drop ] if ;
94
95 TUPLE: rsa handle disposed ;
96
97 : <rsa> ( handle -- rsa ) f rsa boa ;
98
99 M: rsa dispose* handle>> RSA_free ;
100
101 : generate-eph-rsa-key ( ctx -- )
102     [ handle>> ]
103     [
104         config>> ephemeral-key-bits>> RSA_F4 f f RSA_generate_key
105         dup ssl-error <rsa> &dispose handle>>
106     ] bi
107     SSL_CTX_set_tmp_rsa ssl-error ;
108
109 : <openssl-context> ( config ctx -- context )
110     openssl-context new
111         swap >>handle
112         swap >>config
113         V{ } clone >>aliens
114         H{ } clone >>sessions ;
115
116 M: openssl <secure-context> ( config -- context )
117     maybe-init-ssl
118     [
119         dup method>> ssl-method SSL_CTX_new
120         dup ssl-error <openssl-context> |dispose
121         {
122             [ set-session-cache ]
123             [ load-certificate-chain ]
124             [ set-default-password ]
125             [ use-private-key-file ]
126             [ load-verify-locations ]
127             [ set-verify-depth ]
128             [ load-dh-params ]
129             [ generate-eph-rsa-key ]
130             [ ]
131         } cleave
132     ] with-destructors ;
133
134 M: openssl-context dispose*
135     [ aliens>> [ free ] each ]
136     [ sessions>> values [ SSL_SESSION_free ] each ]
137     [ handle>> SSL_CTX_free ]
138     tri ;
139
140 TUPLE: ssl-handle file handle connected disposed ;
141
142 SYMBOL: default-secure-context
143
144 : context-expired? ( context -- ? )
145     dup [ handle>> expired? ] [ drop t ] if ;
146
147 : current-secure-context ( -- ctx )
148     secure-context get [
149         default-secure-context get dup context-expired? [
150             drop
151             <secure-config> <secure-context> default-secure-context set-global
152             current-secure-context
153         ] when
154     ] unless* ;
155
156 : <ssl-handle> ( fd -- ssl )
157     current-secure-context handle>> SSL_new dup ssl-error
158     f f ssl-handle boa ;
159
160 M: ssl-handle dispose*
161     [ handle>> SSL_free ] [ file>> dispose ] bi ;
162
163 : check-verify-result ( ssl-handle -- )
164     SSL_get_verify_result dup X509_V_OK =
165     [ drop ] [ verify-message certificate-verify-error ] if ;
166
167 : common-name ( certificate -- host )
168     X509_get_subject_name
169     NID_commonName 256 <byte-array>
170     [ 256 X509_NAME_get_text_by_NID ] keep
171     swap -1 = [ drop f ] [ latin1 alien>string ] if ;
172
173 : common-names-match? ( expected actual -- ? )
174     [ >lower ] bi@ "*." ?head [ tail? ] [ = ] if ;
175
176 : check-common-name ( host ssl-handle -- )
177     SSL_get_peer_certificate common-name
178     2dup common-names-match?
179     [ 2drop ] [ common-name-verify-error ] if ;
180
181 M: openssl check-certificate ( host ssl -- )
182     current-secure-context config>> verify>> [
183         handle>>
184         [ nip check-verify-result ]
185         [ check-common-name ]
186         2bi
187     ] [ 2drop ] if ;
188
189 : get-session ( addrspec -- session/f )
190     current-secure-context sessions>> at
191     dup expired? [ drop f ] when ;
192
193 : save-session ( session addrspec -- )
194     current-secure-context sessions>> set-at ;
195
196 openssl secure-socket-backend set-global