Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
btwise
openssl
提交
cddd424a
O
openssl
项目概览
btwise
/
openssl
通知
1
Star
0
Fork
0
代码
文件
提交
分支
Tags
贡献者
分支图
Diff
Issue
0
列表
看板
标记
里程碑
合并请求
0
DevOps
流水线
流水线任务
计划
Wiki
0
Wiki
分析
仓库
DevOps
项目成员
Pages
O
openssl
项目概览
项目概览
详情
发布
仓库
仓库
文件
提交
分支
标签
贡献者
分支图
比较
Issue
0
Issue
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
Pages
DevOps
DevOps
流水线
流水线任务
计划
分析
分析
仓库分析
DevOps
Wiki
0
Wiki
成员
成员
收起侧边栏
关闭侧边栏
动态
分支图
创建新Issue
流水线任务
提交
Issue看板
体验新版 GitCode,发现更多精彩内容 >>
提交
cddd424a
编写于
12月 29, 2015
作者:
V
Viktor Dukhovni
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
DANE s_client support
Reviewed-by:
N
Richard Levitte
<
levitte@openssl.org
>
上级
0c1badc8
变更
2
隐藏空白更改
内联
并排
Showing
2 changed file
with
263 addition
and
2 deletion
+263
-2
apps/s_client.c
apps/s_client.c
+222
-2
doc/apps/s_client.pod
doc/apps/s_client.pod
+41
-0
未找到文件。
apps/s_client.c
浏览文件 @
cddd424a
...
...
@@ -138,6 +138,7 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <openssl/e_os2.h>
/*
...
...
@@ -183,6 +184,7 @@ extern int verify_error;
extern
int
verify_return_error
;
extern
int
verify_quiet
;
static
char
*
prog
;
static
int
async
=
0
;
static
int
c_nbio
=
0
;
static
int
c_tlsextdebug
=
0
;
...
...
@@ -202,6 +204,21 @@ static int c_brief = 0;
static
void
print_stuff
(
BIO
*
berr
,
SSL
*
con
,
int
full
);
static
int
ocsp_resp_cb
(
SSL
*
s
,
void
*
arg
);
static
int
saved_errno
;
static
void
save_errno
(
void
)
{
saved_errno
=
errno
;
errno
=
0
;
}
static
int
restore_errno
(
void
)
{
int
ret
=
errno
;
errno
=
saved_errno
;
return
ret
;
}
#ifndef OPENSSL_NO_PSK
/* Default PSK identity and key */
static
char
*
psk_identity
=
"Client_identity"
;
...
...
@@ -455,6 +472,143 @@ static int serverinfo_cli_parse_cb(SSL *s, unsigned int ext_type,
return
1
;
}
/*
* Hex decoder that tolerates optional whitespace. Returns number of bytes
* produced, advances inptr to end of input string.
*/
static
ossl_ssize_t
hexdecode
(
const
char
**
inptr
,
void
*
result
)
{
unsigned
char
**
out
=
(
unsigned
char
**
)
result
;
const
char
*
in
=
*
inptr
;
unsigned
char
*
ret
=
OPENSSL_malloc
(
strlen
(
in
)
/
2
);
unsigned
char
*
cp
=
ret
;
uint8_t
byte
;
int
nibble
=
0
;
if
(
ret
==
NULL
)
return
-
1
;
for
(
byte
=
0
;
*
in
;
++
in
)
{
char
c
;
if
(
isspace
(
*
in
))
continue
;
c
=
tolower
(
*
in
);
if
(
'0'
<=
c
&&
c
<=
'9'
)
{
byte
|=
c
-
'0'
;
}
else
if
(
'a'
<=
c
&&
c
<=
'f'
)
{
byte
|=
c
-
'a'
+
10
;
}
else
{
OPENSSL_free
(
ret
);
return
0
;
}
if
((
nibble
^=
1
)
==
0
)
{
*
cp
++
=
byte
;
byte
=
0
;
}
else
{
byte
<<=
4
;
}
}
if
(
nibble
!=
0
)
{
OPENSSL_free
(
ret
);
return
0
;
}
*
inptr
=
in
;
return
cp
-
(
*
out
=
ret
);
}
/*
* Decode unsigned 0..255, returns 1 on success, <= 0 on failure. Advances
* inptr to next field skipping leading whitespace.
*/
static
ossl_ssize_t
checked_uint8
(
const
char
**
inptr
,
void
*
out
)
{
uint8_t
*
result
=
(
uint8_t
*
)
out
;
const
char
*
in
=
*
inptr
;
char
*
endp
;
long
v
;
int
e
;
save_errno
();
v
=
strtol
(
in
,
&
endp
,
10
);
e
=
restore_errno
();
if
(((
v
==
LONG_MIN
||
v
==
LONG_MAX
)
&&
e
==
ERANGE
)
||
endp
==
in
||
!
isspace
(
*
endp
)
||
v
!=
(
*
result
=
(
uint8_t
)
v
))
{
return
-
1
;
}
for
(
in
=
endp
;
isspace
(
*
in
);
++
in
)
continue
;
*
inptr
=
in
;
return
1
;
}
static
int
tlsa_import_rr
(
SSL
*
con
,
const
char
*
rrdata
)
{
int
ret
;
uint8_t
usage
;
uint8_t
selector
;
uint8_t
mtype
;
unsigned
char
*
data
=
NULL
;
const
char
*
cp
=
rrdata
;
ossl_ssize_t
len
=
0
;
struct
tlsa_field
{
void
*
var
;
const
char
*
name
;
ossl_ssize_t
(
*
parser
)(
const
char
**
,
void
*
);
}
tlsa_fields
[]
=
{
{
&
usage
,
"usage"
,
checked_uint8
},
{
&
selector
,
"selector"
,
checked_uint8
},
{
&
mtype
,
"mtype"
,
checked_uint8
},
{
&
data
,
"data"
,
hexdecode
},
{
NULL
,
}
};
struct
tlsa_field
*
f
;
for
(
f
=
tlsa_fields
;
f
->
var
;
++
f
)
{
/* Returns number of bytes produced, advances cp to next field */
if
((
len
=
f
->
parser
(
&
cp
,
f
->
var
))
<=
0
)
{
BIO_printf
(
bio_err
,
"%s: warning: bad TLSA %s field in: %s
\n
"
,
prog
,
f
->
name
,
rrdata
);
return
0
;
}
}
/* The data field is last, so len is its length */
ret
=
SSL_dane_tlsa_add
(
con
,
usage
,
selector
,
mtype
,
data
,
len
);
OPENSSL_free
(
data
);
if
(
ret
==
0
)
{
ERR_print_errors
(
bio_err
);
BIO_printf
(
bio_err
,
"%s: warning: unusable TLSA rrdata: %s
\n
"
,
prog
,
rrdata
);
return
0
;
}
if
(
ret
<
0
)
{
ERR_print_errors
(
bio_err
);
BIO_printf
(
bio_err
,
"%s: warning: error loading TLSA rrdata: %s
\n
"
,
prog
,
rrdata
);
return
0
;
}
return
ret
;
}
static
int
tlsa_import_rrset
(
SSL
*
con
,
STACK_OF
(
OPENSSL_STRING
)
*
rrset
)
{
int
num
=
sk_OPENSSL_STRING_num
(
rrset
);
int
count
=
0
;
int
i
;
for
(
i
=
0
;
i
<
num
;
++
i
)
{
char
*
rrdata
=
sk_OPENSSL_STRING_value
(
rrset
,
i
);
if
(
tlsa_import_rr
(
con
,
rrdata
)
>
0
)
++
count
;
}
return
count
>
0
;
}
typedef
enum
OPTION_choice
{
OPT_ERR
=
-
1
,
OPT_EOF
=
0
,
OPT_HELP
,
OPT_HOST
,
OPT_PORT
,
OPT_CONNECT
,
OPT_UNIX
,
OPT_XMPPHOST
,
OPT_VERIFY
,
...
...
@@ -478,7 +632,8 @@ typedef enum OPTION_choice {
OPT_V_ENUM
,
OPT_X_ENUM
,
OPT_S_ENUM
,
OPT_FALLBACKSCSV
,
OPT_NOCMDS
,
OPT_PROXY
OPT_FALLBACKSCSV
,
OPT_NOCMDS
,
OPT_PROXY
,
OPT_DANE_TLSA_DOMAIN
,
OPT_DANE_TLSA_RRDATA
}
OPTION_CHOICE
;
OPTIONS
s_client_options
[]
=
{
...
...
@@ -503,6 +658,9 @@ OPTIONS s_client_options[] = {
"Do not load the default certificates file"
},
{
"no-CApath"
,
OPT_NOCAPATH
,
'-'
,
"Do not load certificates from the default certificates directory"
},
{
"dane_tlsa_domain"
,
OPT_DANE_TLSA_DOMAIN
,
's'
,
"DANE TLSA base domain"
},
{
"dane_tlsa_rrdata"
,
OPT_DANE_TLSA_RRDATA
,
's'
,
"DANE TLSA rrdata presentation form"
},
{
"reconnect"
,
OPT_RECONNECT
,
'-'
,
"Drop and re-make the connection with the same Session-ID"
},
{
"pause"
,
OPT_PAUSE
,
'-'
,
"Sleep after each read and write system call"
},
...
...
@@ -648,11 +806,13 @@ int s_client_main(int argc, char **argv)
SSL_EXCERT
*
exc
=
NULL
;
SSL_CONF_CTX
*
cctx
=
NULL
;
STACK_OF
(
OPENSSL_STRING
)
*
ssl_args
=
NULL
;
char
*
dane_tlsa_domain
=
NULL
;
STACK_OF
(
OPENSSL_STRING
)
*
dane_tlsa_rrset
=
NULL
;
STACK_OF
(
X509_CRL
)
*
crls
=
NULL
;
const
SSL_METHOD
*
meth
=
TLS_client_method
();
char
*
CApath
=
NULL
,
*
CAfile
=
NULL
,
*
cbuf
=
NULL
,
*
sbuf
=
NULL
;
char
*
mbuf
=
NULL
,
*
proxystr
=
NULL
,
*
connectstr
=
NULL
;
char
*
cert_file
=
NULL
,
*
key_file
=
NULL
,
*
chain_file
=
NULL
,
*
prog
;
char
*
cert_file
=
NULL
,
*
key_file
=
NULL
,
*
chain_file
=
NULL
;
char
*
chCApath
=
NULL
,
*
chCAfile
=
NULL
,
*
host
=
SSL_HOST_NAME
;
char
*
inrand
=
NULL
;
char
*
passarg
=
NULL
,
*
pass
=
NULL
,
*
vfyCApath
=
NULL
,
*
vfyCAfile
=
NULL
;
...
...
@@ -1032,6 +1192,18 @@ int s_client_main(int argc, char **argv)
case
OPT_VERIFYCAFILE
:
vfyCAfile
=
opt_arg
();
break
;
case
OPT_DANE_TLSA_DOMAIN
:
dane_tlsa_domain
=
opt_arg
();
break
;
case
OPT_DANE_TLSA_RRDATA
:
if
(
dane_tlsa_rrset
==
NULL
)
dane_tlsa_rrset
=
sk_OPENSSL_STRING_new_null
();
if
(
dane_tlsa_rrset
==
NULL
||
!
sk_OPENSSL_STRING_push
(
dane_tlsa_rrset
,
opt_arg
()))
{
BIO_printf
(
bio_err
,
"%s: Memory allocation failure
\n
"
,
prog
);
goto
end
;
}
break
;
case
OPT_NEXTPROTONEG
:
next_proto_neg_in
=
opt_arg
();
break
;
...
...
@@ -1336,6 +1508,15 @@ int s_client_main(int argc, char **argv)
}
# endif
if
(
dane_tlsa_domain
!=
NULL
)
{
if
(
SSL_CTX_dane_enable
(
ctx
)
<=
0
)
{
BIO_printf
(
bio_err
,
"%s: Error enabling DANE TLSA authentication.
\n
"
,
prog
);
ERR_print_errors
(
bio_err
);
goto
end
;
}
}
con
=
SSL_new
(
ctx
);
if
(
sess_in
)
{
SSL_SESSION
*
sess
;
...
...
@@ -1371,6 +1552,29 @@ int s_client_main(int argc, char **argv)
}
}
if
(
dane_tlsa_domain
!=
NULL
)
{
if
(
SSL_dane_enable
(
con
,
dane_tlsa_domain
)
<=
0
)
{
BIO_printf
(
bio_err
,
"%s: Error enabling DANE TLSA "
"authentication.
\n
"
,
prog
);
ERR_print_errors
(
bio_err
);
goto
end
;
}
if
(
dane_tlsa_rrset
==
NULL
)
{
BIO_printf
(
bio_err
,
"%s: DANE TLSA authentication requires at "
"least one -dane_tlsa_rrset option.
\n
"
,
prog
);
goto
end
;
}
if
(
tlsa_import_rrset
(
con
,
dane_tlsa_rrset
)
<=
0
)
{
BIO_printf
(
bio_err
,
"%s: Failed to import any TLSA "
"records.
\n
"
,
prog
);
goto
end
;
}
}
else
if
(
dane_tlsa_rrset
!=
NULL
)
{
BIO_printf
(
bio_err
,
"%s: DANE TLSA authentication requires the "
"-dane_tlsa_domain option.
\n
"
,
prog
);
goto
end
;
}
re_start:
#ifdef NO_SYS_UN_H
if
(
init_client
(
&
s
,
host
,
port
,
socket_type
)
==
0
)
...
...
@@ -2133,6 +2337,7 @@ int s_client_main(int argc, char **argv)
X509_VERIFY_PARAM_free
(
vpm
);
ssl_excert_free
(
exc
);
sk_OPENSSL_STRING_free
(
ssl_args
);
sk_OPENSSL_STRING_free
(
dane_tlsa_rrset
);
SSL_CONF_CTX_free
(
cctx
);
OPENSSL_clear_free
(
cbuf
,
BUFSIZZ
);
OPENSSL_clear_free
(
sbuf
,
BUFSIZZ
);
...
...
@@ -2153,6 +2358,9 @@ static void print_stuff(BIO *bio, SSL *s, int full)
const
SSL_CIPHER
*
c
;
X509_NAME
*
xn
;
int
i
;
int
mdpth
;
EVP_PKEY
*
mspki
;
const
char
*
peername
;
#ifndef OPENSSL_NO_COMP
const
COMP_METHOD
*
comp
,
*
expansion
;
#endif
...
...
@@ -2214,6 +2422,18 @@ static void print_stuff(BIO *bio, SSL *s, int full)
BIO_number_read
(
SSL_get_rbio
(
s
)),
BIO_number_written
(
SSL_get_wbio
(
s
)));
}
if
((
mdpth
=
SSL_get0_dane_authority
(
s
,
NULL
,
&
mspki
))
>=
0
)
{
uint8_t
usage
,
selector
,
mtype
;
(
void
)
SSL_get0_dane_tlsa
(
s
,
&
usage
,
&
selector
,
&
mtype
,
NULL
,
NULL
);
BIO_printf
(
bio
,
"DANE TLSA %d %d %d %s at depth %d
\n
"
,
usage
,
selector
,
mtype
,
(
mspki
!=
NULL
)
?
"TA public key verified certificate"
:
mdpth
?
"matched TA certificate"
:
"matched EE certificate"
,
mdpth
);
}
if
(
SSL_get_verify_result
(
s
)
==
X509_V_OK
&&
(
peername
=
SSL_get0_peername
(
s
))
!=
NULL
)
BIO_printf
(
bio
,
"Verified peername: %s
\n
"
,
peername
);
BIO_printf
(
bio
,
(
SSL_cache_hit
(
s
)
?
"---
\n
Reused, "
:
"---
\n
New, "
));
c
=
SSL_get_current_cipher
(
s
);
BIO_printf
(
bio
,
"%s, Cipher is %s
\n
"
,
...
...
doc/apps/s_client.pod
浏览文件 @
cddd424a
...
...
@@ -22,6 +22,8 @@ B<openssl> B<s_client>
[B<-CAfile filename>]
[B<-no-CAfile>]
[B<-no-CApath>]
[B<-dane_tlsa_domain domain>]
[B<-dane_tlsa_rrdata rrdata>]
[B<-attime timestamp>]
[B<-check_ss_sig>]
[B<-crl_check>]
...
...
@@ -169,6 +171,45 @@ Do not load the trusted CA certificates from the default file location
Do not load the trusted CA certificates from the default directory location
=item B<-dane_tlsa_domain domain>
Enable RFC6698/RFC7671 DANE TLSA authentication and specify the
TLSA base domain which becomes the default SNI hint and the primary
reference identifier for hostname checks. This must be used in
combination with at least one instance of the B<-dane_tlsa_rrdata>
option below.
When DANE authentication succeeds, the diagnostic output will include
the lowest (closest to 0) depth at which a TLSA record authenticated
a chain certificate. When that TLSA record is a "2 1 0" trust
anchor public key that signed (rather than matched) the top-most
certificate of the chain, the result is reported as "TA public key
verified". Otherwise, either the TLSA record "matched TA certificate"
at a positive depth or else "matched EE certificate" at depth 0.
=item B<-dane_tlsa_rrdata rrdata>
Use one or more times to specify the RRDATA fields of the DANE TLSA
RRset associated with the target service. The B<rrdata> value is
specied in "presentation form", that is four whitespace separated
fields that specify the usage, selector, matching type and associated
data, with the last of these encoded in hexadecimal. Optional
whitespace is ignored in the associated data field. For example:
$ openssl s_client -starttls smtp -connect smtp.example.com:25 \
-dane_tlsa_domain smtp.example.com \
-dane_tlsa_rrdata "2 1 1
B111DD8A1C2091A89BD4FD60C57F0716CCE50FEEFF8137CDBEE0326E 02CF362B" \
-dane_tlsa_rrdata "2 1 1
60B87575447DCBA2A36B7D11AC09FB24A9DB406FEE12D2CC90180517 616E8A18"
CONNECTED(00000003)
...
DANE TLSA 2 1 1 matched TA certificate at depth 1
Verified peername: smtp.example.com
...
Verify return code: 0 (ok)
...
=item B<-attime>, B<-check_ss_sig>, B<-crl_check>, B<-crl_check_all>,
B<explicit_policy>, B<-extended_crl>, B<-ignore_critical>, B<-inhibit_any>,
B<-inhibit_map>, B<-issuer_checks>, B<-partial_chain>, B<-policy>,
...
...
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录