summaryrefslogtreecommitdiff
path: root/ntpd/ntp_crypto.c
diff options
context:
space:
mode:
Diffstat (limited to 'ntpd/ntp_crypto.c')
-rw-r--r--ntpd/ntp_crypto.c157
1 files changed, 101 insertions, 56 deletions
diff --git a/ntpd/ntp_crypto.c b/ntpd/ntp_crypto.c
index e66d5c7..5795ae8 100644
--- a/ntpd/ntp_crypto.c
+++ b/ntpd/ntp_crypto.c
@@ -139,6 +139,7 @@ static int calcomp(struct calendar *pjd1, struct calendar *pjd2)
#define TAI_1972 10 /* initial TAI offset (s) */
#define MAX_LEAP 100 /* max UTC leapseconds (s) */
#define VALUE_LEN (6 * 4) /* min response field length */
+#define MAX_VALLEN (65535 - VALUE_LEN)
#define YEAR (60 * 60 * 24 * 365) /* seconds in year */
/*
@@ -179,8 +180,8 @@ static char *rand_file = NULL; /* random seed file */
*/
static int crypto_verify (struct exten *, struct value *,
struct peer *);
-static int crypto_encrypt (struct exten *, struct value *,
- keyid_t *);
+static int crypto_encrypt (const u_char *, u_int, keyid_t *,
+ struct value *);
static int crypto_alice (struct peer *, struct value *);
static int crypto_alice2 (struct peer *, struct value *);
static int crypto_alice3 (struct peer *, struct value *);
@@ -423,7 +424,6 @@ crypto_recv(
int has_mac; /* length of MAC field */
int authlen; /* offset of MAC field */
associd_t associd; /* association ID */
- tstamp_t tstamp = 0; /* timestamp */
tstamp_t fstamp = 0; /* filestamp */
u_int len; /* extension field length */
u_int code; /* extension field opcode */
@@ -448,11 +448,12 @@ crypto_recv(
*/
authlen = LEN_PKT_NOMAC;
hismode = (int)PKT_MODE((&rbufp->recv_pkt)->li_vn_mode);
- while ((has_mac = rbufp->recv_length - authlen) > MAX_MAC_LEN) {
+ while ((has_mac = rbufp->recv_length - authlen) > (int)MAX_MAC_LEN) {
pkt = (u_int32 *)&rbufp->recv_pkt + authlen / 4;
ep = (struct exten *)pkt;
code = ntohl(ep->opcode) & 0xffff0000;
len = ntohl(ep->opcode) & 0x0000ffff;
+ // HMS: Why pkt[1] instead of ep->associd ?
associd = (associd_t)ntohl(pkt[1]);
rval = XEVNT_OK;
#ifdef DEBUG
@@ -473,9 +474,14 @@ crypto_recv(
}
if (len >= VALUE_LEN) {
- tstamp = ntohl(ep->tstamp);
fstamp = ntohl(ep->fstamp);
vallen = ntohl(ep->vallen);
+ /*
+ * Bug 2761: I hope this isn't too early...
+ */
+ if ( vallen == 0
+ || len - VALUE_LEN < vallen)
+ return XEVNT_LEN;
}
switch (code) {
@@ -526,8 +532,9 @@ crypto_recv(
rval = XEVNT_ERR;
break;
}
+ INSIST(len >= VALUE_LEN);
if (vallen == 0 || vallen > MAXHOSTNAME ||
- len < VALUE_LEN + vallen) {
+ len - VALUE_LEN < vallen) {
rval = XEVNT_LEN;
break;
}
@@ -820,15 +827,24 @@ crypto_recv(
* errors.
*/
if (vallen == (u_int)EVP_PKEY_size(host_pkey)) {
+ u_int32 *cookiebuf = malloc(
+ RSA_size(host_pkey->pkey.rsa));
+ if (!cookiebuf) {
+ rval = XEVNT_CKY;
+ break;
+ }
+
if (RSA_private_decrypt(vallen,
(u_char *)ep->pkt,
- (u_char *)&temp32,
+ (u_char *)cookiebuf,
host_pkey->pkey.rsa,
- RSA_PKCS1_OAEP_PADDING) <= 0) {
+ RSA_PKCS1_OAEP_PADDING) != 4) {
rval = XEVNT_CKY;
+ free(cookiebuf);
break;
} else {
- cookie = ntohl(temp32);
+ cookie = ntohl(*cookiebuf);
+ free(cookiebuf);
}
} else {
rval = XEVNT_CKY;
@@ -1185,8 +1201,9 @@ crypto_xmit(
* choice.
*/
case CRYPTO_CERT | CRYPTO_RESP:
- vallen = ntohl(ep->vallen);
- if (vallen == 0 || vallen > MAXHOSTNAME) {
+ vallen = ntohl(ep->vallen); /* Must be <64k */
+ if (vallen == 0 || vallen > MAXHOSTNAME ||
+ len - VALUE_LEN < vallen) {
rval = XEVNT_LEN;
break;
}
@@ -1336,7 +1353,10 @@ crypto_xmit(
* anything goes wrong.
*/
case CRYPTO_COOK | CRYPTO_RESP:
- if ((opcode & 0xffff) < VALUE_LEN) {
+ vallen = ntohl(ep->vallen); /* Must be <64k */
+ if ( vallen == 0
+ || (vallen >= MAX_VALLEN)
+ || (opcode & 0x0000ffff) < VALUE_LEN + vallen) {
rval = XEVNT_LEN;
break;
}
@@ -1344,8 +1364,8 @@ crypto_xmit(
tcookie = cookie;
else
tcookie = peer->hcookie;
- if ((rval = crypto_encrypt(ep, &vtemp, &tcookie)) ==
- XEVNT_OK) {
+ if ((rval = crypto_encrypt((const u_char *)ep->pkt, vallen, &tcookie, &vtemp))
+ == XEVNT_OK) {
len = crypto_send(fp, &vtemp, start);
value_free(&vtemp);
}
@@ -1485,13 +1505,16 @@ crypto_verify(
* up to the next word (4 octets).
*/
vallen = ntohl(ep->vallen);
- if (vallen == 0)
+ if ( vallen == 0
+ || vallen > MAX_VALLEN)
return (XEVNT_LEN);
i = (vallen + 3) / 4;
siglen = ntohl(ep->pkt[i++]);
- if (len < VALUE_LEN + ((vallen + 3) / 4) * 4 + ((siglen + 3) /
- 4) * 4)
+ if ( siglen > MAX_VALLEN
+ || len - VALUE_LEN < ((vallen + 3) / 4) * 4
+ || len - VALUE_LEN - ((vallen + 3) / 4) * 4
+ < ((siglen + 3) / 4) * 4)
return (XEVNT_LEN);
/*
@@ -1549,6 +1572,7 @@ crypto_verify(
* proventic bit. What a relief.
*/
EVP_VerifyInit(&ctx, peer->digest);
+ /* XXX: the "+ 12" needs to be at least documented... */
EVP_VerifyUpdate(&ctx, (u_char *)&ep->tstamp, vallen + 12);
if (EVP_VerifyFinal(&ctx, (u_char *)&ep->pkt[i], siglen,
pkey) <= 0)
@@ -1561,35 +1585,32 @@ crypto_verify(
/*
- * crypto_encrypt - construct encrypted cookie and signature from
- * extension field and cookie
+ * crypto_encrypt - construct vp (encrypted cookie and signature) from
+ * the public key and cookie.
*
- * Returns
+ * Returns:
* XEVNT_OK success
* XEVNT_CKY bad or missing cookie
* XEVNT_PUB bad or missing public key
*/
static int
crypto_encrypt(
- struct exten *ep, /* extension pointer */
- struct value *vp, /* value pointer */
- keyid_t *cookie /* server cookie */
+ const u_char *ptr, /* Public Key */
+ u_int vallen, /* Length of Public Key */
+ keyid_t *cookie, /* server cookie */
+ struct value *vp /* value pointer */
)
{
EVP_PKEY *pkey; /* public key */
EVP_MD_CTX ctx; /* signature context */
tstamp_t tstamp; /* NTP timestamp */
u_int32 temp32;
- u_int len;
- const u_char *ptr;
u_char *puch;
/*
* Extract the public key from the request.
*/
- len = ntohl(ep->vallen);
- ptr = (void *)ep->pkt;
- pkey = d2i_PublicKey(EVP_PKEY_RSA, NULL, &ptr, len);
+ pkey = d2i_PublicKey(EVP_PKEY_RSA, NULL, &ptr, vallen);
if (pkey == NULL) {
msyslog(LOG_ERR, "crypto_encrypt: %s",
ERR_error_string(ERR_get_error(), NULL));
@@ -1603,9 +1624,9 @@ crypto_encrypt(
tstamp = crypto_time();
vp->tstamp = htonl(tstamp);
vp->fstamp = hostval.tstamp;
- len = EVP_PKEY_size(pkey);
- vp->vallen = htonl(len);
- vp->ptr = emalloc(len);
+ vallen = EVP_PKEY_size(pkey);
+ vp->vallen = htonl(vallen);
+ vp->ptr = emalloc(vallen);
puch = vp->ptr;
temp32 = htonl(*cookie);
if (RSA_public_encrypt(4, (u_char *)&temp32, puch,
@@ -1623,8 +1644,8 @@ crypto_encrypt(
vp->sig = emalloc(sign_siglen);
EVP_SignInit(&ctx, sign_digest);
EVP_SignUpdate(&ctx, (u_char *)&vp->tstamp, 12);
- EVP_SignUpdate(&ctx, vp->ptr, len);
- if (EVP_SignFinal(&ctx, vp->sig, &len, sign_pkey))
+ EVP_SignUpdate(&ctx, vp->ptr, vallen);
+ if (EVP_SignFinal(&ctx, vp->sig, &vallen, sign_pkey))
vp->siglen = htonl(sign_siglen);
return (XEVNT_OK);
}
@@ -1695,6 +1716,9 @@ crypto_ident(
* call in the protocol module.
*
* Returns extension field pointer (no errors)
+ *
+ * XXX: opcode and len should really be 32-bit quantities and
+ * we should make sure that str is not too big.
*/
struct exten *
crypto_args(
@@ -1707,23 +1731,30 @@ crypto_args(
tstamp_t tstamp; /* NTP timestamp */
struct exten *ep; /* extension field pointer */
u_int len; /* extension field length */
+ size_t slen = 0;
tstamp = crypto_time();
len = sizeof(struct exten);
- if (str != NULL)
- len += strlen(str);
+ if (str != NULL) {
+ slen = strlen(str);
+ INSIST(slen < MAX_VALLEN);
+ len += slen;
+ }
ep = emalloc_zero(len);
if (opcode == 0)
return (ep);
+ REQUIRE(0 == (len & ~0x0000ffff));
+ REQUIRE(0 == (opcode & ~0xffff0000));
+
ep->opcode = htonl(opcode + len);
ep->associd = htonl(associd);
ep->tstamp = htonl(tstamp);
ep->fstamp = hostval.tstamp;
ep->vallen = 0;
if (str != NULL) {
- ep->vallen = htonl(strlen(str));
- memcpy((char *)ep->pkt, str, strlen(str));
+ ep->vallen = htonl(slen);
+ memcpy((char *)ep->pkt, str, slen);
}
return (ep);
}
@@ -1736,6 +1767,8 @@ crypto_args(
* Note: it is not polite to send a nonempty signature with zero
* timestamp or a nonzero timestamp with an empty signature, but those
* rules are not enforced here.
+ *
+ * XXX This code won't work on a box with 16-bit ints.
*/
int
crypto_send(
@@ -1745,14 +1778,15 @@ crypto_send(
)
{
u_int len, vallen, siglen, opcode;
- int i, j;
+ u_int i, j;
/*
* Calculate extension field length and check for buffer
* overflow. Leave room for the MAC.
*/
- len = 16;
+ len = 16; /* XXX Document! */
vallen = ntohl(vp->vallen);
+ INSIST(vallen <= MAX_VALLEN);
len += ((vallen + 3) / 4 + 1) * 4;
siglen = ntohl(vp->siglen);
len += ((siglen + 3) / 4 + 1) * 4;
@@ -1773,7 +1807,7 @@ crypto_send(
i = 0;
if (vallen > 0 && vp->ptr != NULL) {
j = vallen / 4;
- if (j * 4 < (int)vallen)
+ if (j * 4 < vallen)
ep->pkt[i + j++] = 0;
memcpy(&ep->pkt[i], vp->ptr, vallen);
i += j;
@@ -1786,13 +1820,14 @@ crypto_send(
ep->pkt[i++] = vp->siglen;
if (siglen > 0 && vp->sig != NULL) {
j = siglen / 4;
- if (j * 4 < (int)siglen)
+ if (j * 4 < siglen)
ep->pkt[i + j++] = 0;
memcpy(&ep->pkt[i], vp->sig, siglen);
i += j;
}
opcode = ntohl(ep->opcode);
ep->opcode = htonl((opcode & 0xffff0000) | len);
+ ENSURE(len <= MAX_VALLEN);
return (len);
}
@@ -1829,7 +1864,6 @@ crypto_update(void)
if (hostval.tstamp == 0)
return;
-
/*
* Sign public key and timestamps. The filestamp is derived from
* the host key file extension from wherever the file was
@@ -1946,7 +1980,7 @@ asn_to_calendar (
struct calendar *pjd /* pointer to result */
)
{
- int len; /* length of ASN1_TIME string */
+ size_t len; /* length of ASN1_TIME string */
char v[24]; /* writable copy of ASN1_TIME string */
unsigned long temp; /* result from strtoul */
@@ -2157,7 +2191,8 @@ crypto_bob(
tstamp_t tstamp; /* NTP timestamp */
BIGNUM *bn, *bk, *r;
u_char *ptr;
- u_int len;
+ u_int len; /* extension field length */
+ u_int vallen = 0; /* value length */
/*
* If the IFF parameters are not valid, something awful
@@ -2172,8 +2207,11 @@ crypto_bob(
/*
* Extract r from the challenge.
*/
- len = ntohl(ep->vallen);
- if ((r = BN_bin2bn((u_char *)ep->pkt, len, NULL)) == NULL) {
+ vallen = ntohl(ep->vallen);
+ len = ntohl(ep->opcode) & 0x0000ffff;
+ if (vallen == 0 || len < VALUE_LEN || len - VALUE_LEN < vallen)
+ return XEVNT_LEN;
+ if ((r = BN_bin2bn((u_char *)ep->pkt, vallen, NULL)) == NULL) {
msyslog(LOG_ERR, "crypto_bob: %s",
ERR_error_string(ERR_get_error(), NULL));
return (XEVNT_ERR);
@@ -2185,7 +2223,7 @@ crypto_bob(
*/
bctx = BN_CTX_new(); bk = BN_new(); bn = BN_new();
sdsa = DSA_SIG_new();
- BN_rand(bk, len * 8, -1, 1); /* k */
+ BN_rand(bk, vallen * 8, -1, 1); /* k */
BN_mod_mul(bn, dsa->priv_key, r, dsa->q, bctx); /* b r mod q */
BN_add(bn, bn, bk);
BN_mod(bn, bn, dsa->q, bctx); /* k + b r mod q */
@@ -2204,30 +2242,37 @@ crypto_bob(
* Encode the values in ASN.1 and sign. The filestamp is from
* the local file.
*/
- len = i2d_DSA_SIG(sdsa, NULL);
- if (len == 0) {
+ vallen = i2d_DSA_SIG(sdsa, NULL);
+ if (vallen == 0) {
msyslog(LOG_ERR, "crypto_bob: %s",
ERR_error_string(ERR_get_error(), NULL));
DSA_SIG_free(sdsa);
return (XEVNT_ERR);
}
+ if (vallen > MAX_VALLEN) {
+ msyslog(LOG_ERR, "crypto_bob: signature is too big: %d",
+ vallen);
+ DSA_SIG_free(sdsa);
+ return (XEVNT_LEN);
+ }
memset(vp, 0, sizeof(struct value));
tstamp = crypto_time();
vp->tstamp = htonl(tstamp);
vp->fstamp = htonl(iffkey_info->fstamp);
- vp->vallen = htonl(len);
- ptr = emalloc(len);
+ vp->vallen = htonl(vallen);
+ ptr = emalloc(vallen);
vp->ptr = ptr;
i2d_DSA_SIG(sdsa, &ptr);
DSA_SIG_free(sdsa);
if (tstamp == 0)
return (XEVNT_OK);
+ /* XXX: more validation to make sure the sign fits... */
vp->sig = emalloc(sign_siglen);
EVP_SignInit(&ctx, sign_digest);
EVP_SignUpdate(&ctx, (u_char *)&vp->tstamp, 12);
- EVP_SignUpdate(&ctx, vp->ptr, len);
- if (EVP_SignFinal(&ctx, vp->sig, &len, sign_pkey))
+ EVP_SignUpdate(&ctx, vp->ptr, vallen);
+ if (EVP_SignFinal(&ctx, vp->sig, &vallen, sign_pkey))
vp->siglen = htonl(sign_siglen);
return (XEVNT_OK);
}
@@ -3048,7 +3093,7 @@ cert_sign(
X509_gmtime_adj(X509_get_notAfter(cert), YEAR);
subj = X509_get_issuer_name(cert);
X509_NAME_add_entry_by_txt(subj, "commonName", MBSTRING_ASC,
- hostval.ptr, strlen(hostval.ptr), -1, 0);
+ hostval.ptr, strlen((const char *)hostval.ptr), -1, 0);
subj = X509_get_subject_name(req);
X509_set_subject_name(cert, subj);
X509_set_pubkey(cert, pkey);
@@ -3089,7 +3134,7 @@ cert_sign(
vp->vallen = htonl(len);
vp->ptr = emalloc(len);
ptr = vp->ptr;
- i2d_X509(cert, &ptr);
+ i2d_X509(cert, (unsigned char **)(intptr_t)&ptr);
vp->siglen = 0;
if (tstamp != 0) {
vp->sig = emalloc(sign_siglen);
@@ -3421,7 +3466,7 @@ cert_parse(
/*
* Check for a certificate loop.
*/
- if (strcmp(hostval.ptr, ret->issuer) == 0) {
+ if (strcmp((const char *)hostval.ptr, ret->issuer) == 0) {
msyslog(LOG_NOTICE,
"cert_parse: certificate trail loop %s",
ret->subject);