Page Menu
Home
Phorge
Search
Configure Global Search
Log In
Files
F4444592
engine.c
No One
Temporary
Actions
Download File
Edit File
Delete File
View Transforms
Subscribe
Flag For Later
Award Token
Size
28 KB
Referenced Files
None
Subscribers
None
engine.c
View Options
#include
<assert.h>
#include
<stdbool.h>
#include
<stdarg.h>
#include
<stdlib.h>
#include
<string.h>
#include
<sys/stat.h>
#include
<uv.h>
#include
"../alloc.h"
#include
"../keychain.h"
#include
"../um_debug.h"
#include
<openssl/crypto.h>
#include
<openssl/err.h>
#include
<openssl/ssl.h>
#include
<openssl/x509.h>
#include
"keys.h"
#if _WIN32
#include
<windows.h>
#ifndef PATH_MAX
#define PATH_MAX MAX_PATH
#endif
#endif
#if __APPLE__
#include
<Security/Security.h>
#endif
struct
boringssl_ctx
{
tls_context
api
;
SSL_CTX
*
ctx
;
int
(
*
cert_verify_f
)(
const
struct
tlsuv_certificate_s
*
cert
,
void
*
v_ctx
);
void
*
verify_ctx
;
unsigned
char
*
alpn_protocols
;
};
struct
boringssl_engine
{
struct
tlsuv_engine_s
api
;
SSL
*
ssl
;
char
*
alpn
;
BIO
*
bio
;
bool
handshake_started
;
io_ctx
io
;
io_read
read_f
;
io_write
write_f
;
unsigned
long
error
;
};
static
int
is_self_signed
(
X509
*
cert
);
static
bool
host_is_ip_literal
(
const
char
*
host
);
static
const
char
*
name_str
(
const
X509_NAME
*
n
);
static
void
init_ssl_context
(
struct
boringssl_ctx
*
c
,
const
char
*
cabuf
,
size_t
cabuf_len
);
static
int
tls_set_own_cert
(
tls_context
*
ctx
,
tlsuv_private_key_t
key
,
tlsuv_certificate_t
cert
);
static
int
set_ca_bundle
(
tls_context
*
tls
,
const
char
*
ca
,
size_t
ca_len
);
tlsuv_engine_t
new_boringssl_engine
(
tls_context
*
ctx
,
const
char
*
host
);
static
int
parse_pkcs7_certs
(
tlsuv_certificate_t
*
chain
,
const
char
*
pkcs7
,
size_t
pkcs7len
);
static
int
load_cert
(
tlsuv_certificate_t
*
cert
,
const
char
*
buf
,
size_t
buflen
);
static
int
generate_csr
(
tlsuv_private_key_t
key
,
char
**
pem
,
size_t
*
pemlen
,
...);
static
int
tls_set_partial_vfy
(
tls_context
*
ctx
,
int
allow
);
static
void
tls_set_cert_verify
(
tls_context
*
ctx
,
int
(
*
verify_f
)(
const
struct
tlsuv_certificate_s
*
cert
,
void
*
v_ctx
),
void
*
v_ctx
);
static
void
set_io
(
tlsuv_engine_t
self
,
io_ctx
io
,
io_read
rdf
,
io_write
wrtf
);
static
void
set_io_fd
(
tlsuv_engine_t
self
,
tlsuv_sock_t
fd
);
static
void
set_protocols
(
tlsuv_engine_t
self
,
const
char
**
protocols
,
int
len
);
static
tls_handshake_state
tls_hs_state
(
tlsuv_engine_t
engine
);
static
tls_handshake_state
tls_continue_hs
(
tlsuv_engine_t
self
);
static
const
char
*
tls_get_alpn
(
tlsuv_engine_t
self
);
static
int
tls_write
(
tlsuv_engine_t
self
,
const
char
*
data
,
size_t
data_len
);
static
int
tls_read
(
tlsuv_engine_t
self
,
char
*
out
,
size_t
*
out_bytes
,
size_t
maxout
);
static
int
tls_close
(
tlsuv_engine_t
self
);
static
int
tls_reset
(
tlsuv_engine_t
self
);
static
void
tls_free
(
tlsuv_engine_t
self
);
static
void
tls_free_ctx
(
tls_context
*
ctx
);
static
const
char
*
tls_lib_version
();
static
const
char
*
tls_eng_error
(
tlsuv_engine_t
self
);
static
void
msg_cb
(
int
write_p
,
int
version
,
int
content_type
,
const
void
*
buf
,
size_t
len
,
SSL
*
ssl
,
void
*
arg
);
static
void
info_cb
(
const
SSL
*
s
,
int
where
,
int
ret
);
static
BIO_METHOD
*
BIO_s_engine
(
void
);
#if _WIN32
static
X509_STORE
*
load_system_certs
();
#endif
static
tls_context
boringssl_context_api
=
{
.
version
=
tls_lib_version
,
.
strerror
=
(
const
char
*
(
*
)(
long
))
tls_error
,
.
new_engine
=
new_boringssl_engine
,
.
free_ctx
=
tls_free_ctx
,
.
set_ca_bundle
=
set_ca_bundle
,
.
set_own_cert
=
tls_set_own_cert
,
.
allow_partial_chain
=
tls_set_partial_vfy
,
.
set_cert_verify
=
tls_set_cert_verify
,
.
parse_pkcs7_certs
=
parse_pkcs7_certs
,
.
load_cert
=
load_cert
,
.
generate_key
=
gen_key
,
.
load_key
=
load_key
,
.
generate_csr_to_pem
=
generate_csr
,
};
static
struct
tlsuv_engine_s
boringssl_engine_api
=
{
.
set_io
=
set_io
,
.
set_io_fd
=
set_io_fd
,
.
set_protocols
=
set_protocols
,
.
handshake_state
=
tls_hs_state
,
.
handshake
=
tls_continue_hs
,
.
get_alpn
=
tls_get_alpn
,
.
close
=
tls_close
,
.
write
=
tls_write
,
.
read
=
tls_read
,
.
reset
=
tls_reset
,
.
free
=
tls_free
,
.
strerror
=
tls_eng_error
,
};
int
configure_boringssl
()
{
return
0
;
}
static
const
char
*
tls_lib_version
()
{
return
OpenSSL_version
(
OPENSSL_VERSION
);
}
const
char
*
tls_error
(
unsigned
long
code
)
{
static
char
err_buf
[
32
];
if
(
code
==
0
)
return
"no error"
;
const
char
*
lib_err
=
ERR_lib_error_string
(
code
);
if
(
lib_err
)
return
lib_err
;
snprintf
(
err_buf
,
sizeof
(
err_buf
),
"error[%lX]"
,
code
);
return
err_buf
;
}
static
const
char
*
tls_eng_error
(
tlsuv_engine_t
self
)
{
struct
boringssl_engine
*
e
=
(
struct
boringssl_engine
*
)
self
;
const
char
*
err
=
ERR_reason_error_string
(
e
->
error
);
return
err
;
}
tls_context
*
new_boringssl_ctx
(
const
char
*
ca
,
size_t
ca_len
)
{
OPENSSL_init_ssl
(
OPENSSL_INIT_SSL_DEFAULT
,
NULL
);
struct
boringssl_ctx
*
c
=
tlsuv__calloc
(
1
,
sizeof
(
struct
boringssl_ctx
));
c
->
api
=
boringssl_context_api
;
init_ssl_context
(
c
,
ca
,
ca_len
);
return
&
c
->
api
;
}
static
X509_STORE
*
load_certs
(
const
char
*
buf
,
size_t
buf_len
)
{
X509_STORE
*
certs
=
X509_STORE_new
();
X509
*
c
;
struct
stat
fstat
;
if
(
stat
(
buf
,
&
fstat
)
==
0
)
{
if
(
fstat
.
st_mode
&
S_IFREG
)
{
if
(
!
X509_STORE_load_locations
(
certs
,
buf
,
NULL
))
{
UM_LOG
(
ERR
,
"failed to load certs from [%s]"
,
buf
);
}
}
else
if
(
fstat
.
st_mode
&
S_IFDIR
)
{
X509_LOOKUP
*
lu
=
X509_STORE_add_lookup
(
certs
,
X509_LOOKUP_hash_dir
());
if
(
lu
==
NULL
||
X509_LOOKUP_add_dir
(
lu
,
buf
,
X509_FILETYPE_PEM
)
!=
1
)
{
UM_LOG
(
ERR
,
"failed to load cert directory from [%s]"
,
buf
);
}
}
else
{
UM_LOG
(
ERR
,
"cert bundle[%s] is not a regular file"
,
buf
);
}
}
else
{
BIO
*
crt_bio
=
BIO_new_mem_buf
(
buf
,
(
int
)
buf_len
);
while
((
c
=
PEM_read_bio_X509
(
crt_bio
,
NULL
,
NULL
,
NULL
))
!=
NULL
)
{
int
root
=
is_self_signed
(
c
);
UM_LOG
(
VERB
,
"%s root[%s]"
,
name_str
(
X509_get_subject_name
(
c
)),
root
?
"true"
:
"false"
);
X509_STORE_add_cert
(
certs
,
c
);
X509_free
(
c
);
}
BIO_free
(
crt_bio
);
}
return
certs
;
}
static
int
load_cert
(
tlsuv_certificate_t
*
cert
,
const
char
*
buf
,
size_t
buflen
)
{
X509_STORE
*
store
=
load_certs
(
buf
,
buflen
);
STACK_OF
(
X509_OBJECT
)
*
certs
=
X509_STORE_get0_objects
(
store
);
int
count
=
sk_X509_OBJECT_num
(
certs
);
if
(
count
==
0
)
{
X509_STORE_free
(
store
);
return
-1
;
}
struct
cert_s
*
crt
=
tlsuv__calloc
(
1
,
sizeof
(
*
crt
));
cert_init
(
crt
);
crt
->
cert
=
store
;
*
cert
=
(
tlsuv_certificate_t
)
crt
;
return
0
;
}
static
int
is_self_signed
(
X509
*
cert
)
{
X509_NAME
*
subj
=
X509_get_subject_name
(
cert
);
X509_NAME
*
issuer
=
X509_get_issuer_name
(
cert
);
if
(
X509_NAME_cmp
(
subj
,
issuer
)
!=
0
)
{
return
0
;
}
EVP_PKEY
*
pub
=
X509_get_pubkey
(
cert
);
if
(
pub
==
NULL
)
{
return
0
;
}
int
ok
=
X509_verify
(
cert
,
pub
);
EVP_PKEY_free
(
pub
);
return
ok
==
1
;
}
static
const
char
*
name_str
(
const
X509_NAME
*
n
)
{
static
char
buf
[
1024
];
BIO
*
b
=
BIO_new
(
BIO_s_mem
());
X509_NAME_print
(
b
,
n
,
0
);
BIO_read
(
b
,
buf
,
sizeof
(
buf
));
BIO_free
(
b
);
return
buf
;
}
#if __APPLE__
static
int
apple_ca_verify
(
int
pre_verify
,
X509_STORE_CTX
*
st
)
{
(
void
)
pre_verify
;
CFMutableArrayRef
certs
=
CFArrayCreateMutable
(
kCFAllocatorDefault
,
10
,
&
kCFTypeArrayCallBacks
);
STACK_OF
(
X509
)
*
chain
=
X509_STORE_CTX_get1_chain
(
st
);
for
(
int
i
=
0
;
i
<
sk_X509_num
(
chain
);
i
++
)
{
X509
*
x
=
sk_X509_value
(
chain
,
i
);
uint8_t
*
der
=
NULL
;
int
der_len
=
i2d_X509
(
x
,
&
der
);
CFDataRef
d
=
CFDataCreate
(
kCFAllocatorDefault
,
der
,
der_len
);
OPENSSL_free
(
der
);
SecCertificateRef
c
=
SecCertificateCreateWithData
(
kCFAllocatorDefault
,
d
);
CFArrayAppendValue
(
certs
,
c
);
CFRelease
(
d
);
CFRelease
(
c
);
}
sk_X509_pop_free
(
chain
,
X509_free
);
SecTrustRef
trust
;
SecPolicyRef
policy
=
SecPolicyCreateBasicX509
();
CFErrorRef
err
=
NULL
;
bool
result
=
SecTrustCreateWithCertificates
(
certs
,
policy
,
&
trust
)
==
errSecSuccess
&&
SecTrustEvaluateWithError
(
trust
,
&
err
);
CFRelease
(
trust
);
CFRelease
(
policy
);
CFRelease
(
certs
);
return
result
;
}
#endif
static
int
set_ca_bundle
(
tls_context
*
tls
,
const
char
*
ca
,
size_t
ca_len
)
{
struct
boringssl_ctx
*
c
=
(
struct
boringssl_ctx
*
)
tls
;
SSL_CTX
*
ctx
=
c
->
ctx
;
SSL_CTX_set_verify
(
ctx
,
SSL_VERIFY_PEER
,
NULL
);
if
(
ca
!=
NULL
)
{
X509_STORE
*
store
=
load_certs
(
ca
,
ca_len
);
SSL_CTX_set0_verify_cert_store
(
ctx
,
store
);
}
else
{
#if _WIN32
X509_STORE
*
sys_ca
=
load_system_certs
();
if
(
sys_ca
!=
NULL
)
{
SSL_CTX_set0_verify_cert_store
(
ctx
,
sys_ca
);
}
#elif __APPLE__
SSL_CTX_set_verify
(
ctx
,
SSL_VERIFY_PEER
,
apple_ca_verify
);
#elif defined(ANDROID) || defined(__ANDROID__)
X509_STORE
*
ca_store
=
SSL_CTX_get_cert_store
(
ctx
);
X509_LOOKUP
*
lu
=
X509_STORE_add_lookup
(
ca_store
,
X509_LOOKUP_hash_dir
());
if
(
lu
!=
NULL
)
{
X509_LOOKUP_add_dir
(
lu
,
"/etc/security/cacerts"
,
X509_FILETYPE_PEM
);
}
#else
SSL_CTX_set_default_verify_paths
(
ctx
);
#endif
}
return
0
;
}
static
void
init_ssl_context
(
struct
boringssl_ctx
*
c
,
const
char
*
cabuf
,
size_t
cabuf_len
)
{
const
SSL_METHOD
*
method
=
TLS_client_method
();
SSL_CTX
*
ctx
=
SSL_CTX_new
(
method
);
if
(
ctx
==
NULL
)
{
ERR_print_errors_fp
(
stderr
);
UM_LOG
(
ERR
,
"FATAL: failed to create SSL_CTX: %s"
,
tls_error
(
ERR_get_error
()));
abort
();
}
SSL_CTX_set_app_data
(
ctx
,
c
);
c
->
ctx
=
ctx
;
set_ca_bundle
((
tls_context
*
)
c
,
cabuf
,
cabuf_len
);
SSL_CTX_set_min_proto_version
(
ctx
,
TLS1_2_VERSION
);
SSL_CTX_set_max_proto_version
(
ctx
,
TLS1_3_VERSION
);
char
*
tls_debug
=
getenv
(
"TLS_DEBUG"
);
if
(
tls_debug
)
{
SSL_CTX_set_msg_callback
(
ctx
,
msg_cb
);
SSL_CTX_set_info_callback
(
ctx
,
info_cb
);
}
}
typedef
struct
string_int_pair_st
{
const
char
*
name
;
int
retval
;
}
STRINT_PAIR
;
static
const
char
*
lookup
(
int
val
,
const
STRINT_PAIR
*
list
,
const
char
*
def
)
{
for
(;
list
->
name
;
++
list
)
{
if
(
list
->
retval
==
val
)
return
list
->
name
;
}
return
def
;
}
static
STRINT_PAIR
handshakes
[]
=
{
{
", HelloRequest"
,
SSL3_MT_HELLO_REQUEST
},
{
", ClientHello"
,
SSL3_MT_CLIENT_HELLO
},
{
", ServerHello"
,
SSL3_MT_SERVER_HELLO
},
{
", HelloVerifyRequest"
,
DTLS1_MT_HELLO_VERIFY_REQUEST
},
{
", NewSessionTicket"
,
SSL3_MT_NEWSESSION_TICKET
},
{
", EndOfEarlyData"
,
SSL3_MT_END_OF_EARLY_DATA
},
{
", EncryptedExtensions"
,
SSL3_MT_ENCRYPTED_EXTENSIONS
},
{
", Certificate"
,
SSL3_MT_CERTIFICATE
},
{
", ServerKeyExchange"
,
SSL3_MT_SERVER_KEY_EXCHANGE
},
{
", CertificateRequest"
,
SSL3_MT_CERTIFICATE_REQUEST
},
{
", ServerHelloDone"
,
SSL3_MT_SERVER_DONE
},
{
", CertificateVerify"
,
SSL3_MT_CERTIFICATE_VERIFY
},
{
", ClientKeyExchange"
,
SSL3_MT_CLIENT_KEY_EXCHANGE
},
{
", Finished"
,
SSL3_MT_FINISHED
},
{
", CertificateStatus"
,
SSL3_MT_CERTIFICATE_STATUS
},
{
", SupplementalData"
,
SSL3_MT_SUPPLEMENTAL_DATA
},
{
", KeyUpdate"
,
SSL3_MT_KEY_UPDATE
},
#ifndef OPENSSL_NO_NEXTPROTONEG
{
", NextProto"
,
SSL3_MT_NEXT_PROTO
},
#endif
{
", MessageHash"
,
SSL3_MT_MESSAGE_HASH
},
{
NULL
}
};
static
STRINT_PAIR
alert_types
[]
=
{
{
" close_notify"
,
0
},
{
" end_of_early_data"
,
1
},
{
" unexpected_message"
,
10
},
{
" bad_record_mac"
,
20
},
{
" decryption_failed"
,
21
},
{
" record_overflow"
,
22
},
{
" decompression_failure"
,
30
},
{
" handshake_failure"
,
40
},
{
" bad_certificate"
,
42
},
{
" unsupported_certificate"
,
43
},
{
" certificate_revoked"
,
44
},
{
" certificate_expired"
,
45
},
{
" certificate_unknown"
,
46
},
{
" illegal_parameter"
,
47
},
{
" unknown_ca"
,
48
},
{
" access_denied"
,
49
},
{
" decode_error"
,
50
},
{
" decrypt_error"
,
51
},
{
" export_restriction"
,
60
},
{
" protocol_version"
,
70
},
{
" insufficient_security"
,
71
},
{
" internal_error"
,
80
},
{
" inappropriate_fallback"
,
86
},
{
" user_canceled"
,
90
},
{
" no_renegotiation"
,
100
},
{
" missing_extension"
,
109
},
{
" unsupported_extension"
,
110
},
{
" certificate_unobtainable"
,
111
},
{
" unrecognized_name"
,
112
},
{
" bad_certificate_status_response"
,
113
},
{
" bad_certificate_hash_value"
,
114
},
{
" unknown_psk_identity"
,
115
},
{
" certificate_required"
,
116
},
{
NULL
}
};
static
STRINT_PAIR
ssl_versions
[]
=
{
{
"SSL 3.0"
,
SSL3_VERSION
},
{
"TLS 1.0"
,
TLS1_VERSION
},
{
"TLS 1.1"
,
TLS1_1_VERSION
},
{
"TLS 1.2"
,
TLS1_2_VERSION
},
{
"TLS 1.3"
,
TLS1_3_VERSION
},
{
"DTLS 1.0"
,
DTLS1_VERSION
},
{
NULL
}
};
static
void
msg_cb
(
int
write_p
,
int
version
,
int
content_type
,
const
void
*
buf
,
size_t
len
,
SSL
*
ssl
,
void
*
arg
)
{
(
void
)
ssl
;
(
void
)
arg
;
const
char
*
str_write_p
=
write_p
?
">>>"
:
"<<<"
;
const
char
*
str_content_type
=
""
,
*
str_details1
=
""
,
*
str_details2
=
""
;
const
char
*
str_version
=
lookup
(
version
,
ssl_versions
,
"???"
);
const
unsigned
char
*
bp
=
buf
;
if
(
version
==
SSL3_VERSION
||
version
==
TLS1_VERSION
||
version
==
TLS1_1_VERSION
||
version
==
TLS1_2_VERSION
||
version
==
TLS1_3_VERSION
||
version
==
DTLS1_VERSION
)
{
switch
(
content_type
)
{
case
20
:
str_content_type
=
", ChangeCipherSpec"
;
break
;
case
21
:
str_content_type
=
", Alert"
;
str_details1
=
", ???"
;
if
(
len
==
2
)
{
switch
(
bp
[
0
])
{
case
1
:
str_details1
=
", warning"
;
break
;
case
2
:
str_details1
=
", fatal"
;
break
;
}
str_details2
=
lookup
((
int
)
bp
[
1
],
alert_types
,
" ???"
);
}
break
;
case
22
:
str_content_type
=
", Handshake"
;
str_details1
=
"???"
;
if
(
len
>
0
)
str_details1
=
lookup
((
int
)
bp
[
0
],
handshakes
,
"???"
);
break
;
case
23
:
str_content_type
=
", ApplicationData"
;
break
;
}
}
else
if
(
version
==
0
&&
content_type
==
SSL3_RT_HEADER
)
{
str_version
=
""
;
str_content_type
=
"TLS Header"
;
}
UM_LOG
(
TRACE
,
"%s %s%s [length %04lx]%s%s"
,
str_write_p
,
str_version
,
str_content_type
,
(
unsigned
long
)
len
,
str_details1
,
str_details2
);
}
void
info_cb
(
const
SSL
*
s
,
int
where
,
int
ret
)
{
const
char
*
str
;
int
w
=
where
&
~
SSL_ST_MASK
;
if
(
w
&
SSL_ST_CONNECT
)
str
=
"SSL_connect"
;
else
if
(
w
&
SSL_ST_ACCEPT
)
str
=
"SSL_accept"
;
else
str
=
"undefined"
;
if
(
where
&
SSL_CB_LOOP
)
{
UM_LOG
(
TRACE
,
"%s:%s"
,
str
,
SSL_state_string_long
(
s
));
}
else
if
(
where
&
SSL_CB_ALERT
)
{
str
=
(
where
&
SSL_CB_READ
)
?
"read"
:
"write"
;
UM_LOG
(
VERB
,
"SSL3 alert %s:%s:%s"
,
str
,
SSL_alert_type_string_long
(
ret
),
SSL_alert_desc_string_long
(
ret
));
}
else
if
(
where
&
SSL_CB_EXIT
)
{
if
(
ret
==
0
)
UM_LOG
(
VERB
,
"%s:failed in %s"
,
str
,
SSL_state_string_long
(
s
));
else
if
(
ret
<
0
)
UM_LOG
(
VERB
,
"%s:error in %s"
,
str
,
SSL_state_string_long
(
s
));
}
}
tlsuv_engine_t
new_boringssl_engine
(
tls_context
*
ctx
,
const
char
*
host
)
{
struct
boringssl_ctx
*
context
=
(
struct
boringssl_ctx
*
)
ctx
;
struct
boringssl_engine
*
engine
=
tlsuv__calloc
(
1
,
sizeof
(
struct
boringssl_engine
));
engine
->
api
=
boringssl_engine_api
;
engine
->
ssl
=
SSL_new
(
context
->
ctx
);
if
(
host
&&
*
host
)
{
if
(
host_is_ip_literal
(
host
))
{
X509_VERIFY_PARAM_set1_ip_asc
(
SSL_get0_param
(
engine
->
ssl
),
host
);
}
else
{
SSL_set_tlsext_host_name
(
engine
->
ssl
,
host
);
SSL_set1_host
(
engine
->
ssl
,
host
);
}
}
SSL_set_connect_state
(
engine
->
ssl
);
SSL_set_app_data
(
engine
->
ssl
,
engine
);
return
&
engine
->
api
;
}
static
bool
host_is_ip_literal
(
const
char
*
host
)
{
struct
sockaddr_in
addr4
;
struct
sockaddr_in6
addr6
;
return
host
!=
NULL
&&
(
uv_inet_pton
(
AF_INET
,
host
,
&
addr4
.
sin_addr
)
==
0
||
uv_inet_pton
(
AF_INET6
,
host
,
&
addr6
.
sin6_addr
)
==
0
);
}
static
void
set_io
(
tlsuv_engine_t
self
,
io_ctx
io
,
io_read
rdf
,
io_write
wrtf
)
{
struct
boringssl_engine
*
e
=
(
struct
boringssl_engine
*
)
self
;
assert
(
e
->
bio
==
NULL
);
#ifdef SSL_OP_IGNORE_UNEXPECTED_EOF
SSL_set_options
(
e
->
ssl
,
SSL_OP_IGNORE_UNEXPECTED_EOF
);
#endif
e
->
bio
=
BIO_new
(
BIO_s_engine
());
BIO_set_data
(
e
->
bio
,
e
);
BIO_set_init
(
e
->
bio
,
true
);
SSL_set_bio
(
e
->
ssl
,
e
->
bio
,
e
->
bio
);
e
->
io
=
io
;
e
->
read_f
=
rdf
;
e
->
write_f
=
wrtf
;
}
static
void
set_io_fd
(
tlsuv_engine_t
self
,
tlsuv_sock_t
fd
)
{
struct
boringssl_engine
*
e
=
(
struct
boringssl_engine
*
)
self
;
assert
(
e
->
bio
==
NULL
);
e
->
bio
=
BIO_new_socket
((
int
)
fd
,
false
);
SSL_set_bio
(
e
->
ssl
,
e
->
bio
,
e
->
bio
);
}
static
void
set_protocols
(
tlsuv_engine_t
self
,
const
char
**
protocols
,
int
len
)
{
struct
boringssl_engine
*
e
=
(
struct
boringssl_engine
*
)
self
;
size_t
protolen
=
0
;
for
(
int
i
=
0
;
i
<
len
;
i
++
)
protolen
+=
strlen
(
protocols
[
i
])
+
1
;
unsigned
char
*
alpn_protocols
=
tlsuv__malloc
(
protolen
+
1
);
unsigned
char
*
p
=
alpn_protocols
;
for
(
int
i
=
0
;
i
<
len
;
i
++
)
{
size_t
plen
=
strlen
(
protocols
[
i
]);
*
p
++
=
(
unsigned
char
)
plen
;
strncpy
((
char
*
)
p
,
protocols
[
i
],
plen
);
p
+=
plen
;
}
*
p
=
0
;
SSL_set_alpn_protos
(
e
->
ssl
,
alpn_protocols
,
(
unsigned
int
)
strlen
((
char
*
)
alpn_protocols
));
tlsuv__free
(
alpn_protocols
);
}
static
int
cert_verify_cb
(
X509_STORE_CTX
*
certs
,
void
*
ctx
)
{
struct
boringssl_ctx
*
c
=
ctx
;
X509_STORE
*
store
=
X509_STORE_new
();
X509
*
crt
=
X509_STORE_CTX_get0_cert
(
certs
);
X509_STORE_add_cert
(
store
,
crt
);
char
n
[
1024
];
X509_NAME_oneline
(
X509_get_subject_name
(
crt
),
n
,
1024
);
UM_LOG
(
VERB
,
"verifying %s"
,
n
);
int
rc
=
1
;
struct
cert_s
cert
;
cert_init
(
&
cert
);
cert
.
cert
=
store
;
if
(
c
->
cert_verify_f
&&
c
->
cert_verify_f
((
const
struct
tlsuv_certificate_s
*
)
&
cert
,
c
->
verify_ctx
)
!=
0
)
{
UM_LOG
(
WARN
,
"verify failed for certificate[%s]"
,
n
);
rc
=
0
;
}
X509_STORE_free
(
store
);
return
rc
;
}
int
tls_set_partial_vfy
(
tls_context
*
ctx
,
int
allow
)
{
struct
boringssl_ctx
*
c
=
(
struct
boringssl_ctx
*
)
ctx
;
X509_VERIFY_PARAM
*
vfy
=
SSL_CTX_get0_param
(
c
->
ctx
);
if
(
allow
)
X509_VERIFY_PARAM_set_flags
(
vfy
,
X509_V_FLAG_PARTIAL_CHAIN
);
else
X509_VERIFY_PARAM_clear_flags
(
vfy
,
X509_V_FLAG_PARTIAL_CHAIN
);
return
0
;
}
static
void
tls_set_cert_verify
(
tls_context
*
ctx
,
int
(
*
verify_f
)(
const
struct
tlsuv_certificate_s
*
cert
,
void
*
v_ctx
),
void
*
v_ctx
)
{
struct
boringssl_ctx
*
c
=
(
struct
boringssl_ctx
*
)
ctx
;
c
->
cert_verify_f
=
verify_f
;
c
->
verify_ctx
=
v_ctx
;
SSL_CTX_set_verify
(
c
->
ctx
,
SSL_VERIFY_PEER
,
NULL
);
SSL_CTX_set_cert_verify_callback
(
c
->
ctx
,
cert_verify_cb
,
c
);
}
static
void
tls_free_ctx
(
tls_context
*
ctx
)
{
struct
boringssl_ctx
*
c
=
(
struct
boringssl_ctx
*
)
ctx
;
if
(
c
->
alpn_protocols
)
{
tlsuv__free
(
c
->
alpn_protocols
);
}
SSL_CTX_free
(
c
->
ctx
);
tlsuv__free
(
c
);
}
static
int
tls_reset
(
tlsuv_engine_t
self
)
{
struct
boringssl_engine
*
e
=
(
struct
boringssl_engine
*
)
self
;
ERR_clear_error
();
e
->
bio
=
NULL
;
if
(
!
SSL_clear
(
e
->
ssl
))
{
int
err
=
SSL_get_error
(
e
->
ssl
,
0
);
UM_LOG
(
ERR
,
"error resetting TLS engine: %d(%s)"
,
err
,
tls_error
(
err
));
return
-1
;
}
return
0
;
}
static
void
tls_free
(
tlsuv_engine_t
self
)
{
struct
boringssl_engine
*
e
=
(
struct
boringssl_engine
*
)
self
;
SSL_free
(
e
->
ssl
);
if
(
e
->
alpn
)
{
tlsuv__free
(
e
->
alpn
);
}
tlsuv__free
(
e
);
}
#define SSL_OP_CHECK(op, desc) do { \
if ((op) != 1) { \
uint32_t err = ERR_get_error(); \
UM_LOG(ERR, "failed to " desc ": %d(%s)", err, tls_error(err)); \
return TLS_ERR; \
} \
} while (0)
static
X509
*
tls_set_cert_internal
(
SSL_CTX
*
ssl
,
X509_STORE
*
store
)
{
STACK_OF
(
X509_OBJECT
)
*
certs
=
X509_STORE_get0_objects
(
store
);
X509
*
crt
=
X509_OBJECT_get0_X509
(
sk_X509_OBJECT_value
(
certs
,
0
));
SSL_CTX_use_certificate
(
ssl
,
crt
);
for
(
int
i
=
1
;
i
<
sk_X509_OBJECT_num
(
certs
);
i
++
)
{
X509
*
x509
=
X509_OBJECT_get0_X509
(
sk_X509_OBJECT_value
(
certs
,
i
));
X509_up_ref
(
x509
);
SSL_CTX_add_extra_chain_cert
(
ssl
,
x509
);
}
return
crt
;
}
static
int
tls_set_own_cert
(
tls_context
*
ctx
,
tlsuv_private_key_t
key
,
tlsuv_certificate_t
cert
)
{
struct
boringssl_ctx
*
c
=
(
struct
boringssl_ctx
*
)
ctx
;
SSL_CTX
*
ssl
=
c
->
ctx
;
SSL_CTX_use_PrivateKey
(
ssl
,
NULL
);
SSL_CTX_use_certificate
(
ssl
,
NULL
);
SSL_CTX_clear_chain_certs
(
ssl
);
if
(
key
==
NULL
)
{
return
0
;
}
struct
cert_s
*
crt
=
(
struct
cert_s
*
)
cert
;
X509_STORE
*
store
=
NULL
;
if
(
crt
==
NULL
)
{
if
(
key
->
get_certificate
)
{
if
(
key
->
get_certificate
(
key
,
(
tlsuv_certificate_t
*
)
&
crt
)
!=
0
)
{
return
-1
;
}
store
=
crt
->
cert
;
free
(
crt
);
}
}
else
{
store
=
crt
->
cert
;
X509_STORE_up_ref
(
crt
->
cert
);
}
if
(
store
==
NULL
)
{
return
-1
;
}
struct
priv_key_s
*
pk
=
(
struct
priv_key_s
*
)
key
;
X509
*
certs
=
tls_set_cert_internal
(
ssl
,
store
);
X509_STORE_free
(
store
);
SSL_OP_CHECK
(
X509_check_private_key
(
certs
,
pk
->
pkey
),
"verify key/cert combo"
);
SSL_OP_CHECK
(
SSL_CTX_use_PrivateKey
(
ssl
,
pk
->
pkey
),
"set private key"
);
return
0
;
}
static
tls_handshake_state
tls_hs_state
(
tlsuv_engine_t
engine
)
{
struct
boringssl_engine
*
eng
=
(
struct
boringssl_engine
*
)
engine
;
if
(
SSL_is_init_finished
(
eng
->
ssl
))
return
TLS_HS_COMPLETE
;
return
eng
->
handshake_started
?
TLS_HS_CONTINUE
:
TLS_HS_BEFORE
;
}
static
int
print_err_cb
(
const
char
*
e
,
size_t
len
,
void
*
v
)
{
(
void
)
v
;
UM_LOG
(
WARN
,
"%.*s"
,
(
int
)
len
,
e
);
return
1
;
}
static
tls_handshake_state
tls_continue_hs
(
tlsuv_engine_t
self
)
{
struct
boringssl_engine
*
eng
=
(
struct
boringssl_engine
*
)
self
;
ERR_clear_error
();
eng
->
handshake_started
=
true
;
int
rc
=
SSL_do_handshake
(
eng
->
ssl
);
if
(
rc
!=
1
)
{
eng
->
error
=
ERR_peek_error
();
ERR_print_errors_cb
(
print_err_cb
,
NULL
);
}
if
(
rc
==
1
)
{
eng
->
error
=
0
;
return
TLS_HS_COMPLETE
;
}
int
err
=
SSL_get_error
(
eng
->
ssl
,
rc
);
if
(
rc
==
0
)
{
UM_LOG
(
ERR
,
"boringssl: handshake was terminated: %s"
,
tls_error
(
eng
->
error
));
return
TLS_HS_ERROR
;
}
if
(
err
==
SSL_ERROR_WANT_READ
||
err
==
SSL_ERROR_WANT_WRITE
)
{
return
TLS_HS_CONTINUE
;
}
UM_LOG
(
ERR
,
"boringssl: handshake was terminated: %s"
,
tls_error
(
eng
->
error
));
return
TLS_HS_ERROR
;
}
static
const
char
*
tls_get_alpn
(
tlsuv_engine_t
self
)
{
struct
boringssl_engine
*
eng
=
(
struct
boringssl_engine
*
)
self
;
const
unsigned
char
*
proto
;
unsigned
int
protolen
;
SSL_get0_alpn_selected
(
eng
->
ssl
,
&
proto
,
&
protolen
);
eng
->
alpn
=
tlsuv__calloc
(
1
,
protolen
+
1
);
strncpy
(
eng
->
alpn
,
(
const
char
*
)
proto
,
protolen
);
return
eng
->
alpn
;
}
static
int
tls_write
(
tlsuv_engine_t
self
,
const
char
*
data
,
size_t
data_len
)
{
struct
boringssl_engine
*
eng
=
(
struct
boringssl_engine
*
)
self
;
ERR_clear_error
();
if
(
data_len
>
INT_MAX
)
data_len
=
INT_MAX
;
size_t
wrote
=
0
;
while
(
data_len
>
wrote
)
{
int
remaining
=
(
int
)(
data_len
-
wrote
);
int
ret
=
SSL_write
(
eng
->
ssl
,
data
+
wrote
,
remaining
);
if
(
ret
<=
0
)
{
int
err
=
SSL_get_error
(
eng
->
ssl
,
ret
);
if
(
err
==
SSL_ERROR_WANT_WRITE
)
{
return
wrote
>
0
?
(
int
)
wrote
:
TLS_AGAIN
;
}
eng
->
error
=
ERR_peek_last_error
();
UM_LOG
(
ERR
,
"boringssl: write[%d] error: %s"
,
err
,
tls_error
(
eng
->
error
));
return
-1
;
}
wrote
+=
(
size_t
)
ret
;
}
return
(
int
)
wrote
;
}
static
int
tls_read
(
tlsuv_engine_t
self
,
char
*
out
,
size_t
*
out_bytes
,
size_t
maxout
)
{
struct
boringssl_engine
*
eng
=
(
struct
boringssl_engine
*
)
self
;
int
err
=
SSL_ERROR_NONE
;
uint8_t
*
writep
=
(
uint8_t
*
)
out
;
size_t
total_out
=
0
;
ERR_clear_error
();
while
(
maxout
-
total_out
>
0
)
{
int
want
=
(
int
)(
maxout
-
total_out
);
int
rc
=
SSL_read
(
eng
->
ssl
,
writep
,
want
);
if
(
rc
<=
0
)
{
err
=
SSL_get_error
(
eng
->
ssl
,
rc
);
break
;
}
total_out
+=
(
size_t
)
rc
;
writep
+=
rc
;
}
if
(
total_out
>
0
)
{
*
out_bytes
=
total_out
;
return
SSL_pending
(
eng
->
ssl
)
?
TLS_MORE_AVAILABLE
:
TLS_OK
;
}
*
out_bytes
=
0
;
if
(
SSL_get_shutdown
(
eng
->
ssl
))
return
TLS_EOF
;
unsigned
long
err_code
=
ERR_peek_last_error
();
switch
(
err
)
{
case
SSL_ERROR_NONE
:
UM_LOG
(
WARN
,
"boringssl read: SSL_ERROR_NONE with 0 bytes read"
);
return
TLS_OK
;
case
SSL_ERROR_ZERO_RETURN
:
return
TLS_EOF
;
case
SSL_ERROR_WANT_WRITE
:
case
SSL_ERROR_WANT_READ
:
return
TLS_AGAIN
;
case
SSL_ERROR_SYSCALL
:
case
SSL_ERROR_SSL
:
eng
->
error
=
err_code
;
UM_LOG
(
WARN
,
"boringssl read[%d]: %lX/%s"
,
err
,
err_code
,
tls_error
(
err_code
));
return
TLS_ERR
;
default
:
UM_LOG
(
WARN
,
"boringssl read: unexpected err[%d] code[%lX]"
,
err
,
err_code
);
break
;
}
return
TLS_OK
;
}
static
int
tls_close
(
tlsuv_engine_t
self
)
{
struct
boringssl_engine
*
eng
=
(
struct
boringssl_engine
*
)
self
;
ERR_clear_error
();
int
rc
=
SSL_shutdown
(
eng
->
ssl
);
if
(
rc
<
0
)
{
int
err
=
SSL_get_error
(
eng
->
ssl
,
rc
);
unsigned
long
err_code
=
ERR_peek_last_error
();
UM_LOG
(
WARN
,
"boringssl shutdown[%d]: %lX/%s"
,
err
,
err_code
,
tls_error
(
err_code
));
}
return
0
;
}
static
int
parse_pkcs7_certs
(
tlsuv_certificate_t
*
chain
,
const
char
*
pkcs7buf
,
size_t
pkcs7len
)
{
BIO
*
buf
=
BIO_new_mem_buf
(
pkcs7buf
,
(
int
)
pkcs7len
);
PKCS7
*
pkcs7
=
PEM_read_bio_PKCS7
(
buf
,
NULL
,
NULL
,
NULL
);
if
(
pkcs7
==
NULL
)
{
BIO_free
(
buf
);
buf
=
BIO_new_mem_buf
(
pkcs7buf
,
(
int
)
pkcs7len
);
pkcs7
=
d2i_PKCS7_bio
(
buf
,
NULL
);
}
if
(
pkcs7
==
NULL
)
{
BIO_free
(
buf
);
return
-1
;
}
STACK_OF
(
X509
)
*
certs
;
if
(
PKCS7_type_is_signed
(
pkcs7
))
certs
=
pkcs7
->
d
.
sign
->
cert
;
else
if
(
PKCS7_type_is_signedAndEnveloped
(
pkcs7
))
certs
=
pkcs7
->
d
.
signed_and_enveloped
->
cert
;
else
{
BIO_free
(
buf
);
PKCS7_free
(
pkcs7
);
return
-1
;
}
X509_STORE
*
store
=
X509_STORE_new
();
for
(
int
i
=
0
;
i
<
sk_X509_num
(
certs
);
i
++
)
{
X509
*
c
=
sk_X509_value
(
certs
,
i
);
X509_STORE_add_cert
(
store
,
c
);
}
struct
cert_s
*
c
=
tlsuv__calloc
(
1
,
sizeof
(
*
c
));
cert_init
(
c
);
c
->
cert
=
store
;
*
chain
=
(
tlsuv_certificate_t
)
c
;
PKCS7_free
(
pkcs7
);
BIO_free
(
buf
);
return
0
;
}
static
int
generate_csr
(
tlsuv_private_key_t
key
,
char
**
pem
,
size_t
*
pemlen
,
...)
{
struct
priv_key_s
*
privkey
=
(
struct
priv_key_s
*
)
key
;
int
ret
=
0
;
const
char
*
op
=
NULL
;
EVP_PKEY
*
pk
=
privkey
->
pkey
;
X509_REQ
*
req
=
X509_REQ_new
();
X509_NAME
*
subj
=
X509_REQ_get_subject_name
(
req
);
BIO
*
b
=
BIO_new
(
BIO_s_mem
());
va_list
va
;
va_start
(
va
,
pemlen
);
while
(
true
)
{
char
*
id
=
va_arg
(
va
,
char
*
);
if
(
id
==
NULL
)
break
;
const
uint8_t
*
val
=
va_arg
(
va
,
uint8_t
*
);
if
(
val
==
NULL
)
break
;
X509_NAME_add_entry_by_txt
(
subj
,
id
,
MBSTRING_ASC
,
val
,
-1
,
-1
,
0
);
}
va_end
(
va
);
#define ssl_check(OP) do { \
op = #OP; \
if ((OP) == 0) { \
ret = ERR_get_error(); \
goto on_error; \
} \
} while (0)
ssl_check
(
X509_REQ_set_pubkey
(
req
,
pk
));
ssl_check
(
X509_REQ_sign
(
req
,
pk
,
EVP_sha256
()));
ssl_check
(
PEM_write_bio_X509_REQ
(
b
,
req
));
on_error
:
if
(
ret
)
{
UM_LOG
(
WARN
,
"%s => %s"
,
op
,
tls_error
(
ret
));
}
else
{
size_t
len
=
BIO_ctrl_pending
(
b
);
*
pem
=
tlsuv__calloc
(
1
,
len
+
1
);
BIO_read
(
b
,
*
pem
,
(
int
)
len
);
if
(
pemlen
)
*
pemlen
=
len
;
}
BIO_free
(
b
);
X509_REQ_free
(
req
);
return
ret
;
}
#if _WIN32
#include
<wincrypt.h>
#pragma comment (lib, "crypt32.lib")
static
X509_STORE
*
load_system_certs
()
{
X509_STORE
*
store
=
X509_STORE_new
();
X509
*
c
;
HCERTSTORE
hCertStore
;
PCCERT_CONTEXT
pCertContext
=
NULL
;
if
(
!
(
hCertStore
=
CertOpenSystemStore
(
0
,
"ROOT"
)))
{
UM_LOG
(
ERR
,
"The first system store did not open."
);
return
store
;
}
while
((
pCertContext
=
CertEnumCertificatesInStore
(
hCertStore
,
pCertContext
))
!=
NULL
)
{
c
=
d2i_X509
(
NULL
,
(
const
uint8_t
**
)
&
pCertContext
->
pbCertEncoded
,
(
long
)
pCertContext
->
cbCertEncoded
);
X509_STORE_add_cert
(
store
,
c
);
}
CertFreeCertificateContext
(
pCertContext
);
CertCloseStore
(
hCertStore
,
0
);
return
store
;
}
#endif
static
int
engine_bio_write
(
BIO
*
b
,
const
char
*
data
,
int
len
)
{
struct
boringssl_engine
*
e
=
BIO_get_data
(
b
);
assert
(
e
);
assert
(
e
->
write_f
);
ssize_t
r
=
e
->
write_f
(
e
->
io
,
data
,
(
size_t
)
len
);
if
(
r
>
0
)
{
return
(
int
)
r
;
}
if
(
r
==
0
)
{
BIO_set_retry_write
(
b
);
}
return
-1
;
}
static
int
engine_bio_read
(
BIO
*
b
,
char
*
data
,
int
len
)
{
struct
boringssl_engine
*
e
=
BIO_get_data
(
b
);
assert
(
e
);
assert
(
e
->
read_f
);
ssize_t
r
=
e
->
read_f
(
e
->
io
,
data
,
(
size_t
)
len
);
if
(
r
>
0
)
{
return
(
int
)
r
;
}
if
(
r
==
0
)
{
BIO_set_retry_read
(
b
);
}
return
-1
;
}
static
int
engine_bio_puts
(
BIO
*
b
,
const
char
*
str
)
{
return
engine_bio_write
(
b
,
str
,
(
int
)
strlen
(
str
));
}
static
long
engine_bio_ctrl
(
BIO
*
b
,
int
cmd
,
long
num
,
void
*
ptr
)
{
(
void
)
b
;
(
void
)
num
;
(
void
)
ptr
;
switch
(
cmd
)
{
case
BIO_CTRL_FLUSH
:
case
BIO_CTRL_DGRAM_QUERY_MTU
:
return
1
;
default
:
return
0
;
}
}
static
int
engine_bio_create
(
BIO
*
b
)
{
BIO_set_init
(
b
,
0
);
BIO_set_data
(
b
,
NULL
);
return
1
;
}
static
int
engine_bio_destroy
(
BIO
*
b
)
{
if
(
b
==
NULL
)
return
0
;
BIO_set_data
(
b
,
NULL
);
BIO_set_init
(
b
,
0
);
return
1
;
}
static
BIO_METHOD
*
BIO_s_engine
(
void
)
{
static
BIO_METHOD
*
engine
=
NULL
;
if
(
engine
==
NULL
)
{
engine
=
BIO_meth_new
(
BIO_TYPE_SOURCE_SINK
,
"tlsuv-engine"
);
BIO_meth_set_write
(
engine
,
engine_bio_write
);
BIO_meth_set_read
(
engine
,
engine_bio_read
);
BIO_meth_set_puts
(
engine
,
engine_bio_puts
);
BIO_meth_set_ctrl
(
engine
,
engine_bio_ctrl
);
BIO_meth_set_create
(
engine
,
engine_bio_create
);
BIO_meth_set_destroy
(
engine
,
engine_bio_destroy
);
}
return
engine
;
}
File Metadata
Details
Attached
Mime Type
text/x-c
Expires
Sat, May 2, 10:22 AM (2 d)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
542268
Default Alt Text
engine.c (28 KB)
Attached To
Mode
rANT Ant
Attached
Detach File
Event Timeline
Log In to Comment