Skip to content
GitLab
Menu
Why GitLab
Pricing
Contact Sales
Explore
Why GitLab
Pricing
Contact Sales
Explore
Sign in
Get free trial
Commits on Source (3)
NS-KE-client off the ground far enough to check certificates
· 9948b076
Hal Murray
authored
Feb 07, 2019
9948b076
Setup C2S and S2C
· 5ee06547
Hal Murray
authored
Feb 08, 2019
5ee06547
NTS-KE-server is off the ground
· f89d1134
Hal Murray
authored
Feb 09, 2019
f89d1134
Hide whitespace changes
Inline
Side-by-side
include/ntpd.h
View file @
f89d1134
...
...
@@ -421,6 +421,7 @@ extern const uint8_t num_refclock_conf;
#endif
/* nts.c */
void
nts_start_server
(
void
);
bool
nts_probe
(
struct
peer
*
peer
);
int
nts_client_ke_request
(
struct
ntscfg_t
*
);
int
nts_server_ke_verify
(
struct
ntscfg_t
*
);
...
...
include/nts.h
View file @
f89d1134
...
...
@@ -4,6 +4,8 @@
#ifndef GUARD_NTS_H
#define GUARD_NTS_H
#include
<openssl/ssl.h>
#define NTS_MAX_COOKIES 8
/* RFC 4.1.6 */
#define NTS_COOKIELEN 128
/* placeholder - see RFC 6 */
...
...
@@ -21,11 +23,20 @@ struct ntscfg_t {
uint32_t
expire
;
};
// FIXME AEAD_AES_SIV_CMAC_256
// We are using AEAD_AES_SIV_CMAC_256, from RFC 5297
// There is no clean API yet
#define IANA_AEAD_AES_SIV_CMAC_256 15
#define AEAD_AES_SIV_CMAC_256_KEYLEN 32
#define NTS_MAX_KEYLEN 64
/* Client-side state per connection to server */
struct
ntsstate_t
{
char
cookies
[
NTS_MAX_COOKIES
][
NTS_COOKIELEN
];
int
current_cookie
;
int
cookie_count
;
uint8_t
c2s
[
NTS_MAX_KEYLEN
],
s2c
[
NTS_MAX_KEYLEN
];
int
keylen
;
};
/* Configuration data for an NTS server or client instance */
...
...
@@ -41,4 +52,7 @@ struct ntsconfig_t {
extern
struct
ntsconfig_t
ntsconfig
;
bool
nts_make_keys
(
SSL
*
ssl
,
uint8_t
*
c2s
,
uint8_t
*
s2c
,
int
keylen
);
#endif
/* GUARD_NTS_H */
libntp/ssl_init.c
View file @
f89d1134
...
...
@@ -33,8 +33,10 @@ ssl_init(void)
return
;
#if OPENSSL_VERSION_NUMBER < 0x10100000L || defined(LIBRESSL_VERSION_NUMBER)
SSL_library_init
();
OpenSSL_add_all_digests
();
OpenSSL_add_all_ciphers
();
SSL_load_error_strings
();
atexit
(
&
atexit_ssl_cleanup
);
#endif
...
...
ntpd/ntp_proto.c
View file @
f89d1134
...
...
@@ -829,6 +829,13 @@ transmit(
return
;
}
/* Does server need NTS lookup? */
if
(
peer
->
cfg
.
nts_cfg
.
flags
&
FLAG_NTS
)
{
peer
->
cfg
.
nts_cfg
.
flags
&=
!
FLAG_NTS
;
nts_probe
(
peer
);
return
;
}
/* Does server need DNS lookup? */
if
(
peer
->
cfg
.
flags
&
FLAG_DNS
)
{
peer
->
outdate
=
current_time
;
...
...
ntpd/ntpd.c
View file @
f89d1134
...
...
@@ -500,9 +500,7 @@ ntpdmain(
int
pipe_fds
[
2
];
int
rc
;
int
exit_code
;
# ifdef SIGDANGER
struct
sigaction
sa
;
# endif
# endif
/* HAVE_WORKING_FORK*/
int
op
;
...
...
@@ -629,6 +627,10 @@ ntpdmain(
# endif
/* HAVE_WORKING_FORK */
}
/* Ignore SIGPIPE - from OpenSSL */
sa
.
sa_handler
=
SIG_IGN
;
sigaction
(
SIGPIPE
,
&
sa
,
NULL
);
/*
* Set up signals we pay attention to locally.
*/
...
...
@@ -902,6 +904,9 @@ ntpdmain(
msyslog
(
LOG_ERR
,
"statistics directory %s does not exist or is unwriteable, error %s"
,
statsdir
,
strerror
(
errno
));
}
if
(
ntsconfig
.
ntsenable
)
nts_start_server
();
mainloop
();
/* unreachable, mainloop() never returns */
}
...
...
ntpd/nts.c
View file @
f89d1134
...
...
@@ -15,7 +15,15 @@
#include
"ntp_types.h"
#include
"ntpd.h"
struct
ntsconfig_t
ntsconfig
;
struct
ntsconfig_t
ntsconfig
=
{
.
ntsenable
=
false
,
.
mintls
=
0
,
.
maxtls
=
0
,
.
tlsciphers
=
NULL
,
.
tlsciphersuites
=
NULL
,
.
ca
=
NULL
,
.
cert
=
NULL
};
/* By design, there is no per-client-side state on the server */
...
...
ntpd/nts_client.c
View file @
f89d1134
...
...
@@ -16,6 +16,7 @@
#endif
#include
<openssl/ssl.h>
#include
<openssl/x509.h>
#include
"ntp_types.h"
#include
"ntpd.h"
...
...
@@ -28,6 +29,9 @@ bool nts_probe(struct peer * peer) {
SSL_CTX
*
ctx
;
SSL
*
ssl
;
int
server
=
0
;
X509
*
cert
=
NULL
;
uint8_t
buff
[
1000
];
int
transfered
;
server
=
open_TCP_socket
(
peer
->
hostname
);
if
(
-
1
==
server
)
return
false
;
...
...
@@ -35,33 +39,120 @@ bool nts_probe(struct peer * peer) {
// No error checking yet.
// Ugly since most SSL routines return 1 on success.
// Fedora 29: 0x1010101fL 1.1.1a
// Fedora 28: 0x1010009fL 1.1.0i
// Fedora 29: 0x1010101fL 1.1.1a
// Fedora 28: 0x1010009fL 1.1.0i
// CentOS 6: 0x1000105fL 1.0.1e
// NetBSD 8: 0x100020bfL 1.0.2k
// FreeBSD 12: 0x1010101fL 1.1.1a-freebsd
#if (OPENSSL_VERSION_NUMBER > 0x1010000fL)
ctx
=
SSL_CTX_new
(
TLS_client_method
());
SSL_CTX_set_min_proto_version
(
ctx
,
TLS1_2_VERSION
);
// FIXME
SSL_CTX_set_max_proto_version
(
ctx
,
0
);
#else
/* Older versions of OpenSSL don't support min/max version requests.
* That's OK, since we don't want anything older than 1.2 and
* they don't support anything newer. */
ctx
=
SSL_CTX_new
(
TLSv1_2_client_method
());
if
(
1
)
// FIXME if (non-default version request)
msyslog
(
LOG_INFO
,
"NTSc: can't set min/max TLS versions."
);
#endif
#if (OPENSSL_VERSION_NUMBER > 0x1010000fL)
SSL_CTX_set_default_verify_file
(
ctx
);
// Use system root certs
#else
// FIXME
#endif
SSL_CTX_set_default_verify_paths
(
ctx
);
// Use system root certs
#if (OPENSSL_VERSION_NUMBER > 0x1010000fL)
// FIXME
SSL_CTX_set_min_proto_version
(
ctx
,
TLS1_2_VERSION
);
SSL_CTX_set_max_proto_version
(
ctx
,
0
);
#else
// FIXME
#endif
if
(
NULL
!=
ntsconfig
.
tlsciphers
)
{
if
(
1
!=
SSL_CTX_set_cipher_list
(
ctx
,
ntsconfig
.
tlsciphers
))
{
msyslog
(
LOG_ERR
,
"NTSc: error setting TLS ciphers"
);
}
}
if
(
NULL
!=
ntsconfig
.
tlsciphersuites
)
{
if
(
1
!=
SSL_CTX_set_ciphersuites
(
ctx
,
ntsconfig
.
tlsciphersuites
))
{
msyslog
(
LOG_ERR
,
"NTSc: error setting TLS ciphersuites"
);
}
}
ssl
=
SSL_new
(
ctx
);
SSL_set_fd
(
ssl
,
server
);
SSL_set_tlsext_host_name
(
ssl
,
peer
->
hostname
);
SSL_connect
(
ssl
);
SSL_do_handshake
(
ssl
);
switch
(
SSL_version
(
ssl
))
{
#ifdef TLS1_3_VERSION
case
TLS1_3_VERSION
:
msyslog
(
LOG_INFO
,
"NTSc: Using TLS1.3"
);
break
;
#endif
case
TLS1_2_VERSION
:
msyslog
(
LOG_INFO
,
"NTSc: Using TLS1.2"
);
break
;
default:
msyslog
(
LOG_INFO
,
"NTSc: Strange version: %d,
\"
%s
\"
"
,
SSL_version
(
ssl
),
SSL_get_version
(
ssl
));
break
;
}
/* This may be clutter, but this is how to do it. */
msyslog
(
LOG_INFO
,
"NTSc: Using %s with %d secret bits"
,
SSL_get_cipher_name
(
ssl
),
SSL_get_cipher_bits
(
ssl
,
NULL
));
cert
=
SSL_get_peer_certificate
(
ssl
);
if
(
NULL
==
cert
)
{
msyslog
(
LOG_INFO
,
"NTSc: No certificate"
);
}
else
{
X509_NAME
*
certname
;
char
name
[
200
];
int
certok
;
certname
=
X509_get_subject_name
(
cert
);
X509_NAME_oneline
(
certname
,
name
,
sizeof
(
name
));
msyslog
(
LOG_INFO
,
"NTSc: certificate subject name: %s"
,
name
);
certname
=
X509_get_issuer_name
(
cert
);
X509_NAME_oneline
(
certname
,
name
,
sizeof
(
name
));
msyslog
(
LOG_INFO
,
"NTSc: certificate issuer name: %s"
,
name
);
certok
=
SSL_get_verify_result
(
ssl
);
if
(
X509_V_OK
==
certok
)
{
msyslog
(
LOG_INFO
,
"NTSc: certificate is valid."
);
}
else
{
msyslog
(
LOG_ERR
,
"NTSc: certificate invalid: %d"
,
certok
);
}
}
// FIXME AEAD_AES_SIV_CMAC_256
/* We are using AEAD_AES_SIV_CMAC_256, from RFC 5297
* There is no clean API yet.
*/
peer
->
nts_state
.
keylen
=
AEAD_AES_SIV_CMAC_256_KEYLEN
;
nts_make_keys
(
ssl
,
peer
->
nts_state
.
c2s
,
peer
->
nts_state
.
s2c
,
peer
->
nts_state
.
keylen
);
{
uint8_t
req
[
16
]
=
{
0x00
,
0x01
,
0x00
,
0x02
,
0x00
,
0x00
,
0x00
,
0x04
,
0x00
,
0x02
,
0x00
,
0x0f
,
0x80
,
0x00
,
0x00
,
0x00
};
transfered
=
SSL_write
(
ssl
,
req
,
sizeof
(
req
));
if
(
sizeof
(
req
)
!=
transfered
)
{
msyslog
(
LOG_ERR
,
"NTSc: write failed: %d, %m"
,
transfered
);
goto
bail
;
}
transfered
=
SSL_read
(
ssl
,
buff
,
sizeof
(
buff
));
if
(
0
>
transfered
)
{
msyslog
(
LOG_ERR
,
"NTSc: read failed: %d, %m"
,
transfered
);
goto
bail
;
}
msyslog
(
LOG_ERR
,
"NTSc: read %d bytes"
,
transfered
);
}
SSL_shutdown
(
ssl
);
// unpack buffer
bail:
SSL_free
(
ssl
);
close
(
server
);
SSL_CTX_free
(
ctx
);
...
...
@@ -72,32 +163,36 @@ bool nts_probe(struct peer * peer) {
int
open_TCP_socket
(
const
char
*
hostname
)
{
struct
addrinfo
hints
;
struct
addrinfo
*
answer
;
sockaddr_u
sockaddr
;
int
gai_rc
,
err
;
int
sockfd
;
#ifdef HAVE_RES_INIT
res_init
();
res_init
();
/* see comment in ntp_dns */
#endif
ZERO
(
hints
);
hints
.
ai_protocol
=
IPPROTO_TCP
;
hints
.
ai_socktype
=
SOCK_STREAM
;
hints
.
ai_family
=
AF_UNSPEC
;
gai_rc
=
getaddrinfo
(
hostname
,
"
ntp
"
,
&
hints
,
&
answer
);
gai_rc
=
getaddrinfo
(
hostname
,
"
8123
"
,
&
hints
,
&
answer
);
// FIXME
if
(
0
!=
gai_rc
)
{
msyslog
(
LOG_INFO
,
"
DNS
: nts_probe: DNS error: %d, %s"
,
msyslog
(
LOG_INFO
,
"
NTSc
: nts_probe: DNS error: %d, %s"
,
gai_rc
,
gai_strerror
(
gai_rc
));
return
-
1
;
}
memcpy
(
&
sockaddr
,
answer
->
ai_addr
,
answer
->
ai_addrlen
);
msyslog
(
LOG_INFO
,
"NTSc: nts_probe connecting to %s=%s"
,
hostname
,
socktoa
(
&
sockaddr
));
sockfd
=
socket
(
AF_INET
,
SOCK_STREAM
,
0
);
if
(
-
1
==
sockfd
)
{
msyslog
(
LOG_INFO
,
"
DNS
: nts_probe: no socket: %m"
);
msyslog
(
LOG_INFO
,
"
NTSc
: nts_probe: no socket: %m"
);
}
else
{
// Use first answer
err
=
connect
(
sockfd
,
answer
->
ai_addr
,
answer
->
ai_addrlen
);
if
(
-
1
==
err
)
{
msyslog
(
LOG_INFO
,
"
DNS
: nts_probe: can't connect: %m"
);
msyslog
(
LOG_INFO
,
"
NTSc
: nts_probe: can't connect: %m"
);
close
(
sockfd
);
sockfd
=
-
1
;
}
...
...
@@ -107,4 +202,35 @@ int open_TCP_socket(const char *hostname) {
return
sockfd
;
}
bool
nts_make_keys
(
SSL
*
ssl
,
uint8_t
*
c2s
,
uint8_t
*
s2c
,
int
keylen
)
{
// char *label = "EXPORTER-network-time-security/1";
// Subject: [Ntp] [NTS4NTP] info for NTS developers
// From: Martin Langer <mart.langer@ostfalia.de>
// Date: Tue, 15 Jan 2019 11:40:13 +0100
// bug in OpenSSL 1.1.1a
const
char
*
label
=
"EXPORTER-nts/1"
;
unsigned
char
context
[
5
]
=
{
0x00
,
0x00
,
0x00
,
0x0f
,
0x00
};
if
(
1
!=
SSL_export_keying_material
(
ssl
,
c2s
,
keylen
,
label
,
strlen
(
label
),
context
,
5
,
1
))
{
msyslog
(
LOG_ERR
,
"NTS: Error making c2s
\n
"
);
return
false
;
// ERR_print_errors_fp(stderr);
}
context
[
4
]
=
0x01
;
if
(
1
!=
SSL_export_keying_material
(
ssl
,
s2c
,
keylen
,
label
,
strlen
(
label
),
context
,
5
,
1
))
{
msyslog
(
LOG_ERR
,
"NTS: Error making s2c
\n
"
);
return
false
;
// ERR_print_errors_fp(stderr);
}
// Hack for debugging - obviously not good for security
msyslog
(
LOG_INFO
,
"NTS: C2S %02x %02x %02x %02x %02x
\n
"
,
c2s
[
0
],
c2s
[
1
],
c2s
[
2
],
c2s
[
3
],
c2s
[
4
]);
msyslog
(
LOG_INFO
,
"NTS: S2C %02x %02x %02x %02x %02x
\n
"
,
s2c
[
0
],
s2c
[
1
],
s2c
[
2
],
s2c
[
3
],
s2c
[
4
]);
return
true
;
}
/* end */
ntpd/nts_server.c
0 → 100644
View file @
f89d1134
/*
* nts_server.c - Network Time Security (NTS) server side support
*
* Section references are to
* https://tools.ietf.org/html/draft-ietf-ntp-using-nts-for-ntp-15
*
*/
#include
"config.h"
#include
<signal.h>
#include
<pthread.h>
#include
<unistd.h>
#include
<sys/socket.h>
#include
<openssl/ssl.h>
#include
<openssl/x509.h>
#include
"ntp.h"
#include
"ntpd.h"
#include
"ntp_stdlib.h"
int
create_listener
(
int
port
);
void
*
nts_ke_listener
(
void
*
);
void
nts_ke_request
(
SSL
*
ssl
);
void
nts_start_server
(
void
)
{
SSL_CTX
*
ctx
;
pthread_t
worker
;
sigset_t
block_mask
,
saved_sig_mask
;
int
rc
;
ctx
=
SSL_CTX_new
(
TLS_server_method
());
// FIXME set min/max versions
if
(
1
!=
SSL_CTX_use_certificate_chain_file
(
ctx
,
"/etc/ntp/cert-chain.pem"
))
{
// FIXME log SSL errors
msyslog
(
LOG_ERR
,
"NTSs: can't load cert-chain"
);
}
if
(
1
!=
SSL_CTX_use_PrivateKey_file
(
ctx
,
"/etc/ntp/key.pem"
,
SSL_FILETYPE_PEM
))
{
// FIXME log SSL errors
msyslog
(
LOG_ERR
,
"NTSs: can't load private key"
);
}
if
(
1
!=
SSL_CTX_check_private_key
(
ctx
))
{
msyslog
(
LOG_ERR
,
"NTSs: Private Key doesn't work ******"
);
}
else
{
msyslog
(
LOG_INFO
,
"NTSs: Private Key OK"
);
}
sigfillset
(
&
block_mask
);
pthread_sigmask
(
SIG_BLOCK
,
&
block_mask
,
&
saved_sig_mask
);
rc
=
pthread_create
(
&
worker
,
NULL
,
nts_ke_listener
,
ctx
);
if
(
rc
)
{
msyslog
(
LOG_ERR
,
"NTSs: nts_start_server: error from pthread_create: %m"
);
}
pthread_sigmask
(
SIG_SETMASK
,
&
saved_sig_mask
,
NULL
);
}
void
nts_ke_request
(
SSL
*
ssl
);
void
*
nts_ke_listener
(
void
*
arg
)
{
SSL_CTX
*
ctx
=
(
SSL_CTX
*
)
arg
;
int
sock
;
sock
=
create_listener
(
123
);
if
(
sock
<
0
)
return
NULL
;
while
(
1
)
{
struct
sockaddr
addr
;
uint
len
=
sizeof
(
addr
);
SSL
*
ssl
;
int
client
=
accept
(
sock
,
&
addr
,
&
len
);
if
(
client
<
0
)
{
msyslog
(
LOG_ERR
,
"NTSs: TCP accept failed: %m"
);
continue
;
}
msyslog
(
LOG_INFO
,
"NTSs: TCP accept-ed from %s"
,
socktoa
((
sockaddr_u
*
)
&
addr
));
/* This could/should go in a new thread. */
// FIXME
ssl
=
SSL_new
(
ctx
);
SSL_set_fd
(
ssl
,
client
);
if
(
SSL_accept
(
ssl
)
<=
0
)
{
msyslog
(
LOG_ERR
,
"NTSs: SSL accept failed: %m"
);
close
(
client
);
continue
;
}
msyslog
(
LOG_INFO
,
"NTSs: SSL accept-ed from %s"
,
socktoa
((
sockaddr_u
*
)
&
addr
));
msyslog
(
LOG_INFO
,
"NTSs: Using TLS version %s, cipher %s with %d secret bits"
,
SSL_get_version
(
ssl
),
SSL_get_cipher_name
(
ssl
),
SSL_get_cipher_bits
(
ssl
,
NULL
));
nts_ke_request
(
ssl
);
SSL_shutdown
(
ssl
);
SSL_free
(
ssl
);
close
(
client
);
}
}
void
nts_ke_request
(
SSL
*
ssl
)
{
uint8_t
buff
[
1000
];
size_t
bytes_read
,
bytes_written
;
uint8_t
c2s
[
NTS_MAX_KEYLEN
],
s2c
[
NTS_MAX_KEYLEN
];
int
keylen
=
AEAD_AES_SIV_CMAC_256_KEYLEN
;
bytes_read
=
SSL_read
(
ssl
,
buff
,
sizeof
(
buff
));
if
(
0
>=
bytes_read
)
{
msyslog
(
LOG_INFO
,
"NTSs: SSL_read error"
);
return
;
}
// Hack, echo it back
bytes_written
=
SSL_write
(
ssl
,
buff
,
bytes_read
);
if
(
bytes_written
!=
bytes_read
)
{
msyslog
(
LOG_INFO
,
"NTSs: SSL_write error"
);
return
;
}
if
(
!
nts_make_keys
(
ssl
,
c2s
,
s2c
,
keylen
))
return
;
}
int
create_listener
(
int
port
)
{
int
sock
;
struct
sockaddr_in
addr
;
addr
.
sin_family
=
AF_INET
;
addr
.
sin_port
=
htons
(
port
);
addr
.
sin_addr
.
s_addr
=
htonl
(
INADDR_ANY
);
sock
=
socket
(
AF_INET
,
SOCK_STREAM
,
0
);
if
(
sock
<
0
)
{
msyslog
(
LOG_ERR
,
"NTSs: Can't create socket: %m"
);
return
-
1
;
}
if
(
bind
(
sock
,
(
struct
sockaddr
*
)
&
addr
,
sizeof
(
addr
))
<
0
)
{
msyslog
(
LOG_ERR
,
"NTSs: can't bind: %m"
);
return
-
1
;
}
if
(
listen
(
sock
,
1
)
<
0
)
{
msyslog
(
LOG_ERR
,
"NTSs: can't listen: %m"
);
return
-
1
;
}
return
sock
;
}
/* end */
ntpd/wscript
View file @
f89d1134
...
...
@@ -57,6 +57,7 @@ def build(ctx):
"ntp_restrict.c",
"ntp_util.c",
"nts.c",
"nts_server.c",
"nts_client.c",
"nts_lib.c",
]
...
...