summaryrefslogtreecommitdiffstats
path: root/contrib/ntp/ntpd/ntp_crypto.c
diff options
context:
space:
mode:
authorroberto <roberto@FreeBSD.org>2008-08-22 15:58:00 +0000
committerroberto <roberto@FreeBSD.org>2008-08-22 15:58:00 +0000
commitb85c7169a740b2edf0106ad59fdaa1b0160f823c (patch)
tree2b9fb7f64eacb322e95695e412c923e97ba33e88 /contrib/ntp/ntpd/ntp_crypto.c
parent1d197cfe9feac6bc29537d8e53c30b6435937b95 (diff)
parent7a6072eb585696f8856cd498c3fd194cf49f14c6 (diff)
downloadFreeBSD-src-b85c7169a740b2edf0106ad59fdaa1b0160f823c.zip
FreeBSD-src-b85c7169a740b2edf0106ad59fdaa1b0160f823c.tar.gz
Merge ntpd & friends 4.2.4p5 from vendor/ntp/dist into head. Next commit
will update usr.sbin/ntp to match this. MFC after: 2 weeks
Diffstat (limited to 'contrib/ntp/ntpd/ntp_crypto.c')
-rw-r--r--contrib/ntp/ntpd/ntp_crypto.c1009
1 files changed, 581 insertions, 428 deletions
diff --git a/contrib/ntp/ntpd/ntp_crypto.c b/contrib/ntp/ntpd/ntp_crypto.c
index 3e67703..84adbdd 100644
--- a/contrib/ntp/ntpd/ntp_crypto.c
+++ b/contrib/ntp/ntpd/ntp_crypto.c
@@ -16,6 +16,7 @@
#include "ntp_stdlib.h"
#include "ntp_unixtime.h"
#include "ntp_string.h"
+#include <ntp_random.h>
#include "openssl/asn1_mac.h"
#include "openssl/bn.h"
@@ -98,7 +99,6 @@
* Global cryptodata in host byte order
*/
u_int32 crypto_flags = 0x0; /* status word */
-u_int sys_tai; /* current UTC offset from TAI */
/*
* Global cryptodata in network byte order
@@ -107,6 +107,12 @@ struct cert_info *cinfo = NULL; /* certificate info/value */
struct value hostval; /* host value */
struct value pubkey; /* public key */
struct value tai_leap; /* leapseconds table */
+EVP_PKEY *iffpar_pkey = NULL; /* IFF parameters */
+EVP_PKEY *gqpar_pkey = NULL; /* GQ parameters */
+EVP_PKEY *mvpar_pkey = NULL; /* MV parameters */
+char *iffpar_file = NULL; /* IFF parameters file */
+char *gqpar_file = NULL; /* GQ parameters file */
+char *mvpar_file = NULL; /* MV parameters file */
/*
* Private cryptodata in host byte order
@@ -114,22 +120,17 @@ struct value tai_leap; /* leapseconds table */
static char *passwd = NULL; /* private key password */
static EVP_PKEY *host_pkey = NULL; /* host key */
static EVP_PKEY *sign_pkey = NULL; /* sign key */
-static EVP_PKEY *iffpar_pkey = NULL; /* IFF parameters */
-static EVP_PKEY *gqpar_pkey = NULL; /* GQ parameters */
-static EVP_PKEY *mvpar_pkey = NULL; /* MV parameters */
static const EVP_MD *sign_digest = NULL; /* sign digest */
static u_int sign_siglen; /* sign key length */
static char *rand_file = NULL; /* random seed file */
static char *host_file = NULL; /* host key file */
static char *sign_file = NULL; /* sign key file */
-static char *iffpar_file = NULL; /* IFF parameters file */
-static char *gqpar_file = NULL; /* GQ parameters file */
-static char *mvpar_file = NULL; /* MV parameters file */
static char *cert_file = NULL; /* certificate file */
static char *leap_file = NULL; /* leapseconds file */
-static tstamp_t if_fstamp = 0; /* IFF file stamp */
+static tstamp_t if_fstamp = 0; /* IFF filestamp */
static tstamp_t gq_fstamp = 0; /* GQ file stamp */
-static tstamp_t mv_fstamp = 0; /* MV file stamp */
+static tstamp_t mv_fstamp = 0; /* MV filestamp */
+static u_int ident_scheme = 0; /* server identity scheme */
/*
* Cryptotypes
@@ -192,6 +193,9 @@ session_key(
u_int32 header[10]; /* data in network byte order */
u_int hdlen, len;
+ if (!dstadr)
+ return 0;
+
/*
* Generate the session key and key ID. If the lifetime is
* greater than zero, install the key and call it trusted.
@@ -205,6 +209,7 @@ session_key(
header[3] = htonl(private);
hdlen = 4 * sizeof(u_int32);
break;
+
case AF_INET6:
memcpy(&header[0], &GET_INADDR6(*srcadr),
sizeof(struct in6_addr));
@@ -238,13 +243,17 @@ session_key(
/*
* make_keylist - generate key list
*
+ * Returns
+ * XEVNT_OK success
+ * XEVNT_PER host certificate expired
+ *
* This routine constructs a pseudo-random sequence by repeatedly
* hashing the session key starting from a given source address,
* destination address, private value and the next key ID of the
* preceeding session key. The last entry on the list is saved along
* with its sequence number and public signature.
*/
-void
+int
make_keylist(
struct peer *peer, /* peer structure pointer */
struct interface *dstadr /* interface */
@@ -257,9 +266,12 @@ make_keylist(
keyid_t keyid = 0; /* next key ID */
keyid_t cookie; /* private value */
u_long lifetime;
- u_int len;
+ u_int len, mpoll;
int i;
+ if (!dstadr)
+ return XEVNT_OK;
+
/*
* Allocate the key list if necessary.
*/
@@ -273,9 +285,8 @@ make_keylist(
* NTP_MAXKEY.
*/
while (1) {
- keyid = (u_long)RANDOM & 0xffffffff;
- if (keyid <= NTP_MAXKEY)
- continue;
+ keyid = (ntp_random() + NTP_MAXKEY + 1) & ((1 <<
+ sizeof(keyid_t)) - 1);
if (authhavekey(keyid))
continue;
break;
@@ -288,7 +299,8 @@ make_keylist(
* included in the hash is zero if broadcast mode, the peer
* cookie if client mode or the host cookie if symmetric modes.
*/
- lifetime = min(sys_automax, (unsigned long) NTP_MAXSESSION * (1 <<(peer->kpoll)));
+ mpoll = 1 << min(peer->ppoll, peer->hpoll);
+ lifetime = min(sys_automax, NTP_MAXSESSION * mpoll);
if (peer->hmode == MODE_BROADCAST)
cookie = 0;
else
@@ -298,9 +310,9 @@ make_keylist(
peer->keynumber = i;
keyid = session_key(&dstadr->sin, &peer->srcadr, keyid,
cookie, lifetime);
- lifetime -= 1 << peer->kpoll;
+ lifetime -= mpoll;
if (auth_havekey(keyid) || keyid <= NTP_MAXKEY ||
- lifetime <= (unsigned long)(1 << (peer->kpoll)))
+ lifetime <= mpoll)
break;
}
@@ -320,7 +332,10 @@ make_keylist(
vp->fstamp = hostval.tstamp;
vp->vallen = htonl(sizeof(struct autokey));
vp->siglen = 0;
- if (vp->tstamp != 0) {
+ if (tstamp != 0) {
+ if (tstamp < cinfo->first || tstamp > cinfo->last)
+ return (XEVNT_PER);
+
if (vp->sig == NULL)
vp->sig = emalloc(sign_siglen);
EVP_SignInit(&ctx, sign_digest);
@@ -337,8 +352,9 @@ make_keylist(
if (debug)
printf("make_keys: %d %08x %08x ts %u fs %u poll %d\n",
ntohl(ap->seq), ntohl(ap->key), cookie,
- ntohl(vp->tstamp), ntohl(vp->fstamp), peer->kpoll);
+ ntohl(vp->tstamp), ntohl(vp->fstamp), peer->hpoll);
#endif
+ return (XEVNT_OK);
}
@@ -374,14 +390,10 @@ crypto_recv(
X509 *cert; /* X509 certificate */
char statstr[NTP_MAXSTRLEN]; /* statistics for filegen */
keyid_t cookie; /* crumbles */
+ int hismode; /* packet mode */
int rval = XEVNT_OK;
u_char *ptr;
u_int32 temp32;
-#ifdef KERNEL_PLL
-#if NTP_API > 3
- struct timex ntv; /* kernel interface structure */
-#endif /* NTP_API */
-#endif /* KERNEL_PLL */
/*
* Initialize. Note that the packet has already been checked for
@@ -394,6 +406,7 @@ crypto_recv(
* association ID is saved only if nonzero.
*/
authlen = LEN_PKT_NOMAC;
+ hismode = (int)PKT_MODE((&rbufp->recv_pkt)->li_vn_mode);
while ((has_mac = rbufp->recv_length - authlen) > MAX_MAC_LEN) {
pkt = (u_int32 *)&rbufp->recv_pkt + authlen / 4;
ep = (struct exten *)pkt;
@@ -404,7 +417,7 @@ crypto_recv(
#ifdef DEBUG
if (debug)
printf(
- "crypto_recv: flags 0x%x ext offset %d len %u code %x assocID %d\n",
+ "crypto_recv: flags 0x%x ext offset %d len %u code 0x%x assocID %d\n",
peer->crypto, authlen, len, code >> 16,
associd);
#endif
@@ -413,8 +426,7 @@ crypto_recv(
* Check version number and field length. If bad,
* quietly ignore the packet.
*/
- if (((code >> 24) & 0x3f) != CRYPTO_VN || len < 8 ||
- (len < VALUE_LEN && (code & CRYPTO_RESP))) {
+ if (((code >> 24) & 0x3f) != CRYPTO_VN || len < 8) {
sys_unknownversion++;
code |= CRYPTO_ERROR;
}
@@ -444,15 +456,21 @@ crypto_recv(
* defines the signature scheme. Note the request and
* response are identical, but neither is validated by
* signature. The request is processed here only in
- * symmetric modes. The server name field would be
+ * symmetric modes. The server name field might be
* useful to implement access controls in future.
*/
case CRYPTO_ASSOC:
/*
- * Pass the extension field to the transmit
- * side.
+ * If the machine is running when this message
+ * arrives, the other fellow has reset and so
+ * must we. Otherwise, pass the extension field
+ * to the transmit side.
*/
+ if (peer->crypto) {
+ rval = XEVNT_ERR;
+ break;
+ }
fp = emalloc(len);
memcpy(fp, ep, len);
temp32 = CRYPTO_RESP;
@@ -464,12 +482,13 @@ crypto_recv(
/*
* Discard the message if it has already been
- * stored or the server is not synchronized.
+ * stored or the message has been amputated.
*/
- if (peer->crypto || !fstamp)
+ if (peer->crypto)
break;
- if (len < VALUE_LEN + vallen) {
+ if (vallen == 0 || vallen > MAXHOSTNAME ||
+ len < VALUE_LEN + vallen) {
rval = XEVNT_LEN;
break;
}
@@ -481,51 +500,68 @@ crypto_recv(
* identity are presumed valid, so we skip the
* certificate and identity exchanges and move
* immediately to the cookie exchange which
- * confirms the server signature. If the client
- * has IFF or GC or both, the server must have
- * the same one or both. Otherwise, the default
- * TC scheme is used.
+ * confirms the server signature.
*/
+#ifdef DEBUG
+ if (debug)
+ printf(
+ "crypto_recv: ident host 0x%x server 0x%x\n",
+ crypto_flags, fstamp);
+#endif
+ temp32 = (crypto_flags | ident_scheme) &
+ fstamp & CRYPTO_FLAG_MASK;
if (crypto_flags & CRYPTO_FLAG_PRIV) {
- if (!(fstamp & CRYPTO_FLAG_PRIV))
+ if (!(fstamp & CRYPTO_FLAG_PRIV)) {
rval = XEVNT_KEY;
- else
+ break;
+
+ } else {
fstamp |= CRYPTO_FLAG_VALID |
- CRYPTO_FLAG_VRFY;
- } else if (crypto_flags & CRYPTO_FLAG_MASK &&
- !(crypto_flags & fstamp &
- CRYPTO_FLAG_MASK)) {
+ CRYPTO_FLAG_VRFY |
+ CRYPTO_FLAG_SIGN;
+ }
+ /*
+ * In symmetric modes it is an error if either
+ * peer requests identity and the other peer
+ * does not support it.
+ */
+ } else if ((hismode == MODE_ACTIVE || hismode ==
+ MODE_PASSIVE) && ((crypto_flags | fstamp) &
+ CRYPTO_FLAG_MASK) && !temp32) {
+ rval = XEVNT_KEY;
+ break;
+ /*
+ * It is an error if the client requests
+ * identity and the server does not support it.
+ */
+ } else if (hismode == MODE_CLIENT && (fstamp &
+ CRYPTO_FLAG_MASK) && !temp32) {
rval = XEVNT_KEY;
+ break;
}
/*
- * Discard the message if identity error.
+ * Otherwise, the identity scheme(s) are those
+ * that both client and server support.
*/
- if (rval != XEVNT_OK)
- break;
+ fstamp = temp32 | (fstamp & ~CRYPTO_FLAG_MASK);
/*
- * Discard the message if the host name length
- * is unreasonable or the signature digest NID
- * is not supported.
+ * Discard the message if the signature digest
+ * NID is not supported.
*/
temp32 = (fstamp >> 16) & 0xffff;
dp =
(const EVP_MD *)EVP_get_digestbynid(temp32);
- if (vallen == 0 || vallen > MAXHOSTNAME)
- rval = XEVNT_LEN;
- else if (dp == NULL)
+ if (dp == NULL) {
rval = XEVNT_MD;
- if (rval != XEVNT_OK)
break;
+ }
/*
* Save status word, host name and message
- * digest/signature type. If PC identity, be
- * sure not to sign the certificate.
+ * digest/signature type.
*/
- if (crypto_flags & CRYPTO_FLAG_PRIV)
- fstamp |= CRYPTO_FLAG_SIGN;
peer->crypto = fstamp;
peer->digest = dp;
peer->subject = emalloc(vallen + 1);
@@ -554,12 +590,8 @@ crypto_recv(
case CRYPTO_CERT | CRYPTO_RESP:
/*
- * Discard the message if invalid or identity
- * already confirmed.
+ * Discard the message if invalid.
*/
- if (peer->crypto & CRYPTO_FLAG_VRFY)
- break;
-
if ((rval = crypto_verify(ep, NULL, peer)) !=
XEVNT_OK)
break;
@@ -589,7 +621,7 @@ crypto_recv(
strcpy(peer->issuer, cinfo->issuer);
/*
- * We plug in the public key and group key in
+ * We plug in the public key and lifetime from
* the first certificate received. However, note
* that this certificate might not be signed by
* the server, so we can't check the
@@ -602,7 +634,7 @@ crypto_recv(
peer->pkey = X509_get_pubkey(cert);
X509_free(cert);
}
- peer->flash &= ~TEST10;
+ peer->flash &= ~TEST8;
temp32 = cinfo->nid;
sprintf(statstr, "cert %s 0x%x %s (%u) fs %u",
cinfo->subject, cinfo->flags,
@@ -627,12 +659,13 @@ crypto_recv(
case CRYPTO_IFF | CRYPTO_RESP:
/*
- * Discard the message if invalid or identity
- * already confirmed.
+ * Discard the message if invalid or certificate
+ * trail not trusted.
*/
- if (peer->crypto & CRYPTO_FLAG_VRFY)
+ if (!(peer->crypto & CRYPTO_FLAG_VALID)) {
+ rval = XEVNT_ERR;
break;
-
+ }
if ((rval = crypto_verify(ep, NULL, peer)) !=
XEVNT_OK)
break;
@@ -651,7 +684,7 @@ crypto_recv(
peer->crypto |= CRYPTO_FLAG_VRFY |
CRYPTO_FLAG_PROV;
- peer->flash &= ~TEST10;
+ peer->flash &= ~TEST8;
sprintf(statstr, "iff fs %u",
ntohl(ep->fstamp));
record_crypto_stats(&peer->srcadr, statstr);
@@ -674,12 +707,13 @@ crypto_recv(
case CRYPTO_GQ | CRYPTO_RESP:
/*
- * Discard the message if invalid or identity
- * already confirmed.
+ * Discard the message if invalid or certificate
+ * trail not trusted.
*/
- if (peer->crypto & CRYPTO_FLAG_VRFY)
+ if (!(peer->crypto & CRYPTO_FLAG_VALID)) {
+ rval = XEVNT_ERR;
break;
-
+ }
if ((rval = crypto_verify(ep, NULL, peer)) !=
XEVNT_OK)
break;
@@ -698,7 +732,7 @@ crypto_recv(
peer->crypto |= CRYPTO_FLAG_VRFY |
CRYPTO_FLAG_PROV;
- peer->flash &= ~TEST10;
+ peer->flash &= ~TEST8;
sprintf(statstr, "gq fs %u",
ntohl(ep->fstamp));
record_crypto_stats(&peer->srcadr, statstr);
@@ -714,12 +748,13 @@ crypto_recv(
case CRYPTO_MV | CRYPTO_RESP:
/*
- * Discard the message if invalid or identity
- * already confirmed.
+ * Discard the message if invalid or certificate
+ * trail not trusted.
*/
- if (peer->crypto & CRYPTO_FLAG_VRFY)
+ if (!(peer->crypto & CRYPTO_FLAG_VALID)) {
+ rval = XEVNT_ERR;
break;
-
+ }
if ((rval = crypto_verify(ep, NULL, peer)) !=
XEVNT_OK)
break;
@@ -738,7 +773,7 @@ crypto_recv(
peer->crypto |= CRYPTO_FLAG_VRFY |
CRYPTO_FLAG_PROV;
- peer->flash &= ~TEST10;
+ peer->flash &= ~TEST8;
sprintf(statstr, "mv fs %u",
ntohl(ep->fstamp));
record_crypto_stats(&peer->srcadr, statstr);
@@ -747,47 +782,6 @@ crypto_recv(
printf("crypto_recv: %s\n", statstr);
#endif
break;
-
- /*
- * X509 certificate sign response. Validate the
- * certificate signed by the server and install. Later
- * this can be provided to clients of this server in
- * lieu of the self signed certificate in order to
- * validate the public key.
- */
- case CRYPTO_SIGN | CRYPTO_RESP:
-
- /*
- * Discard the message if invalid or identity
- * not confirmed.
- */
- if (!(peer->crypto & CRYPTO_FLAG_VRFY))
- break;
-
- if ((rval = crypto_verify(ep, NULL, peer)) !=
- XEVNT_OK)
- break;
-
- /*
- * Scan the certificate list to delete old
- * versions and link the newest version first on
- * the list.
- */
- if ((rval = cert_install(ep, peer)) != XEVNT_OK) break;
-
- peer->crypto |= CRYPTO_FLAG_SIGN;
- peer->flash &= ~TEST10;
- temp32 = cinfo->nid;
- sprintf(statstr, "sign %s 0x%x %s (%u) fs %u",
- cinfo->issuer, cinfo->flags,
- OBJ_nid2ln(temp32), temp32,
- ntohl(ep->fstamp));
- record_crypto_stats(&peer->srcadr, statstr);
-#ifdef DEBUG
- if (debug)
- printf("crypto_recv: %s\n", statstr);
-#endif
- break;
/*
* Cookie request in symmetric modes. Roll a random
@@ -797,12 +791,13 @@ crypto_recv(
case CRYPTO_COOK:
/*
- * Discard the message if invalid or identity
- * not confirmed.
+ * Discard the message if invalid or certificate
+ * trail not trusted.
*/
- if (!(peer->crypto & CRYPTO_FLAG_VRFY))
+ if (!(peer->crypto & CRYPTO_FLAG_VALID)) {
+ rval = XEVNT_ERR;
break;
-
+ }
if ((rval = crypto_verify(ep, NULL, peer)) !=
XEVNT_OK)
break;
@@ -817,7 +812,7 @@ crypto_recv(
fp->opcode |= htonl(temp32);
peer->cmmd = fp;
if (peer->crypto & CRYPTO_FLAG_AGREE) {
- peer->flash &= ~TEST10;
+ peer->flash &= ~TEST8;
break;
}
@@ -832,7 +827,7 @@ crypto_recv(
RAND_bytes((u_char *)&peer->pcookie, 4);
peer->crypto &= ~CRYPTO_FLAG_AUTO;
peer->crypto |= CRYPTO_FLAG_AGREE;
- peer->flash &= ~TEST10;
+ peer->flash &= ~TEST8;
sprintf(statstr, "cook %x ts %u fs %u",
peer->pcookie, ntohl(ep->tstamp),
ntohl(ep->fstamp));
@@ -855,9 +850,10 @@ crypto_recv(
* not confirmed or signature not verified with
* respect to the cookie values.
*/
- if (!(peer->crypto & CRYPTO_FLAG_VRFY))
+ if (!(peer->crypto & CRYPTO_FLAG_VRFY)) {
+ rval = XEVNT_ERR;
break;
-
+ }
if ((rval = crypto_verify(ep, &peer->cookval,
peer)) != XEVNT_OK)
break;
@@ -896,7 +892,7 @@ crypto_recv(
else
peer->crypto &= ~CRYPTO_FLAG_AUTO;
peer->crypto |= CRYPTO_FLAG_AGREE;
- peer->flash &= ~TEST10;
+ peer->flash &= ~TEST8;
sprintf(statstr, "cook %x ts %u fs %u",
peer->pcookie, ntohl(ep->tstamp),
ntohl(ep->fstamp));
@@ -924,9 +920,10 @@ crypto_recv(
* not confirmed or signature not verified with
* respect to the receive autokey values.
*/
- if (!(peer->crypto & CRYPTO_FLAG_VRFY))
+ if (!(peer->crypto & CRYPTO_FLAG_VRFY)) {
+ rval = XEVNT_ERR;
break;
-
+ }
if ((rval = crypto_verify(ep, &peer->recval,
peer)) != XEVNT_OK)
break;
@@ -946,7 +943,7 @@ crypto_recv(
bp->key = ntohl(ap->key);
peer->pkeyid = bp->key;
peer->crypto |= CRYPTO_FLAG_AUTO;
- peer->flash &= ~TEST10;
+ peer->flash &= ~TEST8;
sprintf(statstr,
"auto seq %d key %x ts %u fs %u", bp->seq,
bp->key, ntohl(ep->tstamp),
@@ -957,6 +954,49 @@ crypto_recv(
printf("crypto_recv: %s\n", statstr);
#endif
break;
+
+ /*
+ * X509 certificate sign response. Validate the
+ * certificate signed by the server and install. Later
+ * this can be provided to clients of this server in
+ * lieu of the self signed certificate in order to
+ * validate the public key.
+ */
+ case CRYPTO_SIGN | CRYPTO_RESP:
+
+ /*
+ * Discard the message if invalid or not
+ * proventic.
+ */
+ if (!(peer->crypto & CRYPTO_FLAG_PROV)) {
+ rval = XEVNT_ERR;
+ break;
+ }
+ if ((rval = crypto_verify(ep, NULL, peer)) !=
+ XEVNT_OK)
+ break;
+
+ /*
+ * Scan the certificate list to delete old
+ * versions and link the newest version first on
+ * the list.
+ */
+ if ((rval = cert_install(ep, peer)) != XEVNT_OK)
+ break;
+
+ peer->crypto |= CRYPTO_FLAG_SIGN;
+ peer->flash &= ~TEST8;
+ temp32 = cinfo->nid;
+ sprintf(statstr, "sign %s 0x%x %s (%u) fs %u",
+ cinfo->issuer, cinfo->flags,
+ OBJ_nid2ln(temp32), temp32,
+ ntohl(ep->fstamp));
+ record_crypto_stats(&peer->srcadr, statstr);
+#ifdef DEBUG
+ if (debug)
+ printf("crypto_recv: %s\n", statstr);
+#endif
+ break;
/*
* Install leapseconds table in symmetric modes. This
@@ -970,12 +1010,8 @@ crypto_recv(
case CRYPTO_TAI:
/*
- * Discard the message if invalid or identity
- * not confirmed.
+ * Discard the message if invalid.
*/
- if (!(peer->crypto & CRYPTO_FLAG_VRFY))
- break;
-
if ((rval = crypto_verify(ep, NULL, peer)) !=
XEVNT_OK)
break;
@@ -991,7 +1027,7 @@ crypto_recv(
fp->opcode |= htonl(temp32);
peer->cmmd = fp;
if (len <= VALUE_LEN) {
- peer->flash &= ~TEST10;
+ peer->flash &= ~TEST8;
break;
}
/* fall through */
@@ -999,22 +1035,18 @@ crypto_recv(
case CRYPTO_TAI | CRYPTO_RESP:
/*
- * Discard the message if invalid or identity
- * not confirmed or signature not verified with
- * respect to the leapsecond table values.
+ * If this is a response, discard the message if
+ * signature not verified with respect to the
+ * leapsecond table values.
*/
- if (!(peer->crypto & CRYPTO_FLAG_VRFY))
- break;
-
- if ((rval = crypto_verify(ep, &peer->tai_leap,
- peer)) != XEVNT_OK)
- break;
+ if (peer->cmmd == NULL) {
+ if ((rval = crypto_verify(ep,
+ &peer->tai_leap, peer)) != XEVNT_OK)
+ break;
+ }
/*
- * Initialize peer variables, leapseconds
- * structure and extension field in network byte
- * order. Since a filestamp may have changed,
- * recompute the signatures.
+ * Initialize peer variables with latest update.
*/
peer->tai_leap.tstamp = ep->tstamp;
peer->tai_leap.fstamp = ep->fstamp;
@@ -1035,25 +1067,12 @@ crypto_recv(
tai_leap.ptr = emalloc(vallen);
memcpy(tai_leap.ptr, ep->pkt, vallen);
crypto_update();
- sys_tai = vallen / 4 + TAI_1972 - 1;
}
crypto_flags |= CRYPTO_FLAG_TAI;
peer->crypto |= CRYPTO_FLAG_LEAP;
- peer->flash &= ~TEST10;
-#ifdef KERNEL_PLL
-#if NTP_API > 3
- /*
- * If the kernel cooperates, initialize the
- * current TAI offset.
- */
- ntv.modes = MOD_TAI;
- ntv.constant = sys_tai;
- (void)ntp_adjtime(&ntv);
-#endif /* NTP_API */
-#endif /* KERNEL_PLL */
- sprintf(statstr, "leap %u ts %u fs %u",
- vallen, ntohl(ep->tstamp),
- ntohl(ep->fstamp));
+ peer->flash &= ~TEST8;
+ sprintf(statstr, "leap %u ts %u fs %u", vallen,
+ ntohl(ep->tstamp), ntohl(ep->fstamp));
record_crypto_stats(&peer->srcadr, statstr);
#ifdef DEBUG
if (debug)
@@ -1068,6 +1087,7 @@ crypto_recv(
* valid field length. Remaining checks are below and on
* the transmit side.
*/
+ case CRYPTO_CERT:
case CRYPTO_IFF:
case CRYPTO_GQ:
case CRYPTO_MV:
@@ -1076,7 +1096,6 @@ crypto_recv(
rval = XEVNT_LEN;
break;
}
-
/* fall through */
/*
@@ -1088,7 +1107,7 @@ crypto_recv(
*/
default:
if (code & (CRYPTO_RESP | CRYPTO_ERROR)) {
- rval = XEVNT_LEN;
+ rval = XEVNT_ERR;
} else if ((rval = crypto_verify(ep, NULL,
peer)) == XEVNT_OK) {
fp = emalloc(len);
@@ -1100,24 +1119,27 @@ crypto_recv(
}
/*
- * We log everything except length/format errors and
+ * We don't log length/format/timestamp errors and
* duplicates, which are log clogging vulnerabilities.
* The first error found terminates the extension field
- * scan and we return the laundry to the caller.
+ * scan and we return the laundry to the caller. A
+ * length/format/timestamp error on transmit is
+ * cheerfully ignored, as the message is not sent.
*/
- if (rval != XEVNT_OK) {
+ if (rval > XEVNT_TSP) {
sprintf(statstr,
"error %x opcode %x ts %u fs %u", rval,
code, tstamp, fstamp);
- if (rval > XEVNT_TSP)
- record_crypto_stats(&peer->srcadr,
- statstr);
+ record_crypto_stats(&peer->srcadr, statstr);
report_event(rval, peer);
#ifdef DEBUG
if (debug)
printf("crypto_recv: %s\n", statstr);
#endif
break;
+
+ } else if (rval > XEVNT_OK && (code & CRYPTO_RESP)) {
+ rval = XEVNT_OK;
}
authlen += len;
}
@@ -1148,9 +1170,10 @@ crypto_xmit(
struct peer *peer; /* peer structure pointer */
u_int opcode; /* extension field opcode */
struct exten *fp; /* extension pointers */
- struct cert_info *cp; /* certificate info/value pointer */
+ struct cert_info *cp, *xp; /* certificate info/value pointer */
char certname[MAXHOSTNAME + 1]; /* subject name buffer */
char statstr[NTP_MAXSTRLEN]; /* statistics for filegen */
+ tstamp_t tstamp;
u_int vallen;
u_int len;
struct value vtemp;
@@ -1170,21 +1193,22 @@ crypto_xmit(
fp->associd = htonl(associd);
len = 8;
rval = XEVNT_OK;
+ tstamp = crypto_time();
switch (opcode & 0xffff0000) {
/*
* Send association request and response with status word and
* host name. Note, this message is not signed and the filestamp
- * contains only the status word. We check at this point whether
- * the identity schemes are compatible to save tears later on.
+ * contains only the status word.
*/
case CRYPTO_ASSOC | CRYPTO_RESP:
+ len += crypto_send(fp, &hostval);
+ fp->fstamp = htonl(crypto_flags);
+ break;
+
case CRYPTO_ASSOC:
len += crypto_send(fp, &hostval);
- if (crypto_time() == 0)
- fp->fstamp = 0;
- else
- fp->fstamp = htonl(crypto_flags);
+ fp->fstamp = htonl(crypto_flags | ident_scheme);
break;
/*
@@ -1196,17 +1220,15 @@ crypto_xmit(
vtemp.tstamp = ep->tstamp;
vtemp.fstamp = ep->fstamp;
vtemp.vallen = ep->vallen;
- vtemp.ptr = (unsigned char *)ep->pkt;
+ vtemp.ptr = (u_char *)ep->pkt;
len += crypto_send(fp, &vtemp);
break;
/*
* Send certificate response or sign request. Use the values
- * from the certificate. If the request contains no subject
- * name, assume the name of this host. This is for backwards
- * compatibility. Light the error bit if no certificate with
- * the given subject name is found. Of course, private
- * certificates are never sent.
+ * from the certificate cache. If the request contains no
+ * subject name, assume the name of this host. This is for
+ * backwards compatibility. Private certificates are never sent.
*/
case CRYPTO_SIGN:
case CRYPTO_CERT | CRYPTO_RESP:
@@ -1214,23 +1236,61 @@ crypto_xmit(
if (vallen == 8) {
strcpy(certname, sys_hostname);
} else if (vallen == 0 || vallen > MAXHOSTNAME) {
- opcode |= CRYPTO_ERROR;
+ rval = XEVNT_LEN;
break;
} else {
memcpy(certname, ep->pkt, vallen);
certname[vallen] = '\0';
}
+
+ /*
+ * Find all certificates with matching subject. If a
+ * self-signed, trusted certificate is found, use that.
+ * If not, use the first one with matching subject. A
+ * private certificate is never divulged or signed.
+ */
+ xp = NULL;
for (cp = cinfo; cp != NULL; cp = cp->link) {
if (cp->flags & CERT_PRIV)
continue;
+
if (strcmp(certname, cp->subject) == 0) {
- len += crypto_send(fp, &cp->cert);
- break;
+ if (xp == NULL)
+ xp = cp;
+ if (strcmp(certname, cp->issuer) ==
+ 0 && cp->flags & CERT_TRUST) {
+ xp = cp;
+ break;
+ }
}
}
- if (cp == NULL)
- opcode |= CRYPTO_ERROR;
+
+ /*
+ * Be careful who you trust. If not yet synchronized,
+ * give back an empty response. If certificate not found
+ * or beyond the lifetime, return an error. This is to
+ * avoid a bad dude trying to get an expired certificate
+ * re-signed. Otherwise, send it.
+ *
+ * Note the timestamp and filestamp are taken from the
+ * certificate value structure. For all certificates the
+ * timestamp is the latest signature update time. For
+ * host and imported certificates the filestamp is the
+ * creation epoch. For signed certificates the filestamp
+ * is the creation epoch of the trusted certificate at
+ * the base of the certificate trail. In principle, this
+ * allows strong checking for signature masquerade.
+ */
+ if (tstamp == 0)
+ break;
+
+ if (xp == NULL)
+ rval = XEVNT_CRT;
+ else if (tstamp < xp->first || tstamp > xp->last)
+ rval = XEVNT_SRV;
+ else
+ len += crypto_send(fp, &xp->cert);
break;
/*
@@ -1238,21 +1298,23 @@ crypto_xmit(
*/
case CRYPTO_IFF:
if ((peer = findpeerbyassoc(ep->pkt[0])) == NULL) {
- opcode |= CRYPTO_ERROR;
+ rval = XEVNT_ERR;
break;
}
- if ((rval = crypto_alice(peer, &vtemp)) == XEVNT_OK)
+ if ((rval = crypto_alice(peer, &vtemp)) == XEVNT_OK) {
len += crypto_send(fp, &vtemp);
- value_free(&vtemp);
+ value_free(&vtemp);
+ }
break;
/*
* Send response in Schnorr (IFF) identity scheme.
*/
case CRYPTO_IFF | CRYPTO_RESP:
- if ((rval = crypto_bob(ep, &vtemp)) == XEVNT_OK)
+ if ((rval = crypto_bob(ep, &vtemp)) == XEVNT_OK) {
len += crypto_send(fp, &vtemp);
- value_free(&vtemp);
+ value_free(&vtemp);
+ }
break;
/*
@@ -1260,21 +1322,23 @@ crypto_xmit(
*/
case CRYPTO_GQ:
if ((peer = findpeerbyassoc(ep->pkt[0])) == NULL) {
- opcode |= CRYPTO_ERROR;
+ rval = XEVNT_ERR;
break;
}
- if ((rval = crypto_alice2(peer, &vtemp)) == XEVNT_OK)
+ if ((rval = crypto_alice2(peer, &vtemp)) == XEVNT_OK) {
len += crypto_send(fp, &vtemp);
- value_free(&vtemp);
+ value_free(&vtemp);
+ }
break;
/*
* Send response in Guillou-Quisquater (GQ) identity scheme.
*/
case CRYPTO_GQ | CRYPTO_RESP:
- if ((rval = crypto_bob2(ep, &vtemp)) == XEVNT_OK)
+ if ((rval = crypto_bob2(ep, &vtemp)) == XEVNT_OK) {
len += crypto_send(fp, &vtemp);
- value_free(&vtemp);
+ value_free(&vtemp);
+ }
break;
/*
@@ -1282,21 +1346,23 @@ crypto_xmit(
*/
case CRYPTO_MV:
if ((peer = findpeerbyassoc(ep->pkt[0])) == NULL) {
- opcode |= CRYPTO_ERROR;
+ rval = XEVNT_ERR;
break;
}
- if ((rval = crypto_alice3(peer, &vtemp)) == XEVNT_OK)
+ if ((rval = crypto_alice3(peer, &vtemp)) == XEVNT_OK) {
len += crypto_send(fp, &vtemp);
- value_free(&vtemp);
+ value_free(&vtemp);
+ }
break;
/*
* Send response in MV identity scheme.
*/
case CRYPTO_MV | CRYPTO_RESP:
- if ((rval = crypto_bob3(ep, &vtemp)) == XEVNT_OK)
+ if ((rval = crypto_bob3(ep, &vtemp)) == XEVNT_OK) {
len += crypto_send(fp, &vtemp);
- value_free(&vtemp);
+ value_free(&vtemp);
+ }
break;
/*
@@ -1327,14 +1393,14 @@ crypto_xmit(
*/
case CRYPTO_COOK | CRYPTO_RESP:
if ((opcode & 0xffff) < VALUE_LEN) {
- opcode |= CRYPTO_ERROR;
+ rval = XEVNT_LEN;
break;
}
if (PKT_MODE(xpkt->li_vn_mode) == MODE_SERVER) {
tcookie = cookie;
} else {
if ((peer = findpeerbyassoc(associd)) == NULL) {
- opcode |= CRYPTO_ERROR;
+ rval = XEVNT_ERR;
break;
}
tcookie = peer->pcookie;
@@ -1354,7 +1420,7 @@ crypto_xmit(
*/
case CRYPTO_AUTO | CRYPTO_RESP:
if ((peer = findpeerbyassoc(associd)) == NULL) {
- opcode |= CRYPTO_ERROR;
+ rval = XEVNT_ERR;
break;
}
peer->flags &= ~FLAG_ASSOC;
@@ -1363,8 +1429,8 @@ crypto_xmit(
/*
* Send leapseconds table and signature. Use the values from the
- * tai structure. If no table has been loaded, just send a
- * request.
+ * tai structure. If no table has been loaded, just send an
+ * empty request.
*/
case CRYPTO_TAI:
case CRYPTO_TAI | CRYPTO_RESP:
@@ -1378,22 +1444,24 @@ crypto_xmit(
*/
default:
if (opcode & CRYPTO_RESP)
- opcode |= CRYPTO_ERROR;
+ rval = XEVNT_ERR;
}
/*
- * We ignore length/format errors and duplicates. Other errors
- * are reported to the log and deny further service. To really
- * persistent rascals we toss back a kiss-of-death grenade.
+ * In case of error, flame the log. If a request, toss the
+ * puppy; if a response, return so the sender can flame, too.
*/
- if (rval > XEVNT_TSP) {
+ if (rval != XEVNT_OK) {
opcode |= CRYPTO_ERROR;
sprintf(statstr, "error %x opcode %x", rval, opcode);
record_crypto_stats(srcadr_sin, statstr);
+ report_event(rval, NULL);
#ifdef DEBUG
if (debug)
printf("crypto_xmit: %s\n", statstr);
#endif
+ if (!(opcode & CRYPTO_RESP))
+ return (0);
}
/*
@@ -1405,8 +1473,8 @@ crypto_xmit(
#ifdef DEBUG
if (debug)
printf(
- "crypto_xmit: ext offset %d len %u code %x assocID %d\n",
- start, len, opcode>> 16, associd);
+ "crypto_xmit: flags 0x%x ext offset %d len %u code 0x%x assocID %d\n",
+ crypto_flags, start, len, opcode >> 16, associd);
#endif
return (len);
}
@@ -1423,6 +1491,7 @@ crypto_xmit(
* XEVNT_PUB bad or missing public key
* XEVNT_SGL bad signature length
* XEVNT_SIG signature not verified
+ * XEVNT_ERR protocol error
*/
static int
crypto_verify(
@@ -1433,16 +1502,15 @@ crypto_verify(
{
EVP_PKEY *pkey; /* server public key */
EVP_MD_CTX ctx; /* signature context */
- tstamp_t tstamp; /* timestamp */
- tstamp_t fstamp; /* filestamp */
+ tstamp_t tstamp, tstamp1 = 0; /* timestamp */
+ tstamp_t fstamp, fstamp1 = 0; /* filestamp */
u_int vallen; /* value length */
u_int siglen; /* signature length */
u_int opcode, len;
- int rval;
int i;
/*
- * We require valid opcode and field length, timestamp,
+ * We require valid opcode and field lengths, timestamp,
* filestamp, public key, digest, signature length and
* signature, where relevant. Note that preliminary length
* checks are done in the main loop.
@@ -1457,7 +1525,8 @@ crypto_verify(
* header, no need for further checking.
*/
if (opcode & CRYPTO_ERROR)
- return (XEVNT_LEN);
+ return (XEVNT_ERR);
+
if (opcode & CRYPTO_RESP) {
if (len < VALUE_LEN)
return (XEVNT_LEN);
@@ -1465,91 +1534,93 @@ crypto_verify(
if (len < VALUE_LEN)
return (XEVNT_OK);
}
+
/*
* We have a value header. Check for valid field lengths. The
* field length must be long enough to contain the value header,
- * value and signature. If a request and a previous request of
- * the same type is pending, discard the previous request. If a
- * request but no signature, there is no need for further
- * checking.
+ * value and signature. Note both the value and signature fields
+ * are rounded up to the next word.
*/
vallen = ntohl(ep->vallen);
- if (len < ((VALUE_LEN + vallen + 3) / 4) * 4)
- return (XEVNT_LEN);
-
i = (vallen + 3) / 4;
siglen = ntohl(ep->pkt[i++]);
- if (len < VALUE_LEN + vallen + siglen)
+ if (len < VALUE_LEN + ((vallen + 3) / 4) * 4 + ((siglen + 3) /
+ 4) * 4)
return (XEVNT_LEN);
- if (!(opcode & CRYPTO_RESP)) {
- if (peer->cmmd != NULL) {
- if ((opcode | CRYPTO_RESP) ==
- (ntohl(peer->cmmd->opcode) & 0xffff0000)) {
- free(peer->cmmd);
- peer->cmmd = NULL;
- } else {
- return (XEVNT_LEN);
- }
- }
- if (siglen == 0)
- return (XEVNT_OK);
+ /*
+ * Punt if this is a response with no data. Punt if this is a
+ * request and a previous response is pending.
+ */
+ if (opcode & CRYPTO_RESP) {
+ if (vallen == 0)
+ return (XEVNT_LEN);
+ } else {
+ if (peer->cmmd != NULL)
+ return (XEVNT_LEN);
}
/*
- * We have a signature. Check for valid timestamp and filestamp.
- * The timestamp must not precede the filestamp. The timestamp
- * and filestamp must not precede the corresponding values in
- * the value structure. Once the autokey values have been
- * installed, the timestamp must always be later than the
- * corresponding value in the value structure. Duplicate
- * timestamps are illegal once the cookie has been validated.
+ * Check for valid timestamp and filestamp. If the timestamp is
+ * zero, the sender is not synchronized and signatures are
+ * disregarded. If not, the timestamp must not precede the
+ * filestamp. The timestamp and filestamp must not precede the
+ * corresponding values in the value structure, if present. Once
+ * the autokey values have been installed, the timestamp must
+ * always be later than the corresponding value in the value
+ * structure. Duplicate timestamps are illegal once the cookie
+ * has been validated.
+ */
+ tstamp = ntohl(ep->tstamp);
+ fstamp = ntohl(ep->fstamp);
+ if (tstamp == 0)
+ return (XEVNT_OK);
+
+ if (tstamp < fstamp)
+ return (XEVNT_TSP);
+
+ if (vp != NULL) {
+ tstamp1 = ntohl(vp->tstamp);
+ fstamp1 = ntohl(vp->fstamp);
+ if ((tstamp < tstamp1 || (tstamp == tstamp1 &&
+ (peer->crypto & CRYPTO_FLAG_AUTO))))
+ return (XEVNT_TSP);
+
+ if ((tstamp < fstamp1 || fstamp < fstamp1))
+ return (XEVNT_FSP);
+ }
+
+ /*
+ * Check for valid signature length, public key and digest
+ * algorithm.
*/
- rval = XEVNT_OK;
if (crypto_flags & peer->crypto & CRYPTO_FLAG_PRIV)
pkey = sign_pkey;
else
pkey = peer->pkey;
- tstamp = ntohl(ep->tstamp);
- fstamp = ntohl(ep->fstamp);
- if (tstamp == 0 || tstamp < fstamp) {
- rval = XEVNT_TSP;
- } else if (vp != NULL && (tstamp < ntohl(vp->tstamp) ||
- (tstamp == ntohl(vp->tstamp) && (peer->crypto &
- CRYPTO_FLAG_AUTO)))) {
- rval = XEVNT_TSP;
- } else if (vp != NULL && (tstamp < ntohl(vp->fstamp) || fstamp <
- ntohl(vp->fstamp))) {
- rval = XEVNT_FSP;
-
- /*
- * If a public key and digest is present, and if valid key
- * length, check for valid signature. Note that the first valid
- * signature lights the proventic bit.
- */
- } else if (pkey == NULL || peer->digest == NULL) {
- /* fall through */
- } else if (siglen != (u_int) EVP_PKEY_size(pkey)) {
- rval = XEVNT_SGL;
- } else {
- EVP_VerifyInit(&ctx, peer->digest);
- EVP_VerifyUpdate(&ctx, (u_char *)&ep->tstamp, vallen +
- 12);
- if (EVP_VerifyFinal(&ctx, (u_char *)&ep->pkt[i], siglen,
- pkey)) {
- if (peer->crypto & CRYPTO_FLAG_VRFY)
- peer->crypto |= CRYPTO_FLAG_PROV;
- } else {
- rval = XEVNT_SIG;
- }
+ if (siglen == 0 || pkey == NULL || peer->digest == NULL)
+ return (XEVNT_OK);
+
+ if (siglen != (u_int)EVP_PKEY_size(pkey))
+ return (XEVNT_SGL);
+
+ /*
+ * Darn, I thought we would never get here. Verify the
+ * signature. If the identity exchange is verified, light the
+ * proventic bit. If no client identity scheme is specified,
+ * avoid doing the sign exchange.
+ */
+ EVP_VerifyInit(&ctx, peer->digest);
+ EVP_VerifyUpdate(&ctx, (u_char *)&ep->tstamp, vallen + 12);
+ if (!EVP_VerifyFinal(&ctx, (u_char *)&ep->pkt[i], siglen, pkey))
+ return (XEVNT_SIG);
+
+ if (peer->crypto & CRYPTO_FLAG_VRFY) {
+ peer->crypto |= CRYPTO_FLAG_PROV;
+ if (!(crypto_flags & CRYPTO_FLAG_MASK))
+ peer->crypto |= CRYPTO_FLAG_SIGN;
}
-#ifdef DEBUG
- if (debug > 1)
- printf(
- "crypto_recv: verify %x vallen %u siglen %u ts %u fs %u\n",
- rval, vallen, siglen, tstamp, fstamp);
-#endif
- return (rval);
+ return (XEVNT_OK);
}
@@ -1561,6 +1632,7 @@ crypto_verify(
* XEVNT_OK success
* XEVNT_PUB bad or missing public key
* XEVNT_CKY bad or missing cookie
+ * XEVNT_PER host certificate expired
*/
static int
crypto_encrypt(
@@ -1610,6 +1682,10 @@ crypto_encrypt(
vp->siglen = 0;
if (tstamp == 0)
return (XEVNT_OK);
+
+ if (tstamp < cinfo->first || tstamp > cinfo->last)
+ return (XEVNT_PER);
+
vp->sig = emalloc(sign_siglen);
EVP_SignInit(&ctx, sign_digest);
EVP_SignUpdate(&ctx, (u_char *)&vp->tstamp, 12);
@@ -1642,9 +1718,6 @@ crypto_ident(
* been found and the CRYPTO_FLAG_VALID bit is set, so the
* certificate issuer is valid.
*/
- if (peer->crypto & CRYPTO_FLAG_VRFY)
- return (0);
-
if (peer->ident_pkey != NULL)
EVP_PKEY_free(peer->ident_pkey);
if (peer->crypto & CRYPTO_FLAG_GQ) {
@@ -1688,8 +1761,7 @@ crypto_ident(
}
/*
- * No compatible identity scheme is available. Use the default
- * TC scheme.
+ * No compatible identity scheme is available. Life is hard.
*/
msyslog(LOG_INFO,
"crypto_ident: no compatible identity scheme found");
@@ -1724,6 +1796,9 @@ crypto_args(
len += strlen(str);
ep = emalloc(len);
memset(ep, 0, len);
+ if (opcode == 0)
+ return (ep);
+
ep->opcode = htonl(opcode + len);
/*
@@ -1813,13 +1888,14 @@ void
crypto_update(void)
{
EVP_MD_CTX ctx; /* message digest context */
- struct cert_info *cp, *cpn, **zp; /* certificate info/value */
+ struct cert_info *cp, *cpn; /* certificate info/value */
char statstr[NTP_MAXSTRLEN]; /* statistics for filegen */
tstamp_t tstamp; /* NTP timestamp */
u_int len;
if ((tstamp = crypto_time()) == 0)
return;
+
hostval.tstamp = htonl(tstamp);
/*
@@ -1842,29 +1918,21 @@ crypto_update(void)
/*
* Sign certificates and timestamps. The filestamp is derived
* from the certificate file extension from wherever the file
- * was generated. At the same time expired certificates are
- * expunged.
+ * was generated. Note we do not throw expired certificates
+ * away; they may have signed younger ones.
*/
- zp = &cinfo;
for (cp = cinfo; cp != NULL; cp = cpn) {
cpn = cp->link;
- if (tstamp > cp->last) {
- *zp = cpn;
- cert_free(cp);
- } else {
- cp->cert.tstamp = hostval.tstamp;
- cp->cert.siglen = 0;
- if (cp->cert.sig == NULL)
- cp->cert.sig = emalloc(sign_siglen);
- EVP_SignInit(&ctx, sign_digest);
- EVP_SignUpdate(&ctx, (u_char *)&cp->cert, 12);
- EVP_SignUpdate(&ctx, cp->cert.ptr,
- ntohl(cp->cert.vallen));
- if (EVP_SignFinal(&ctx, cp->cert.sig, &len,
- sign_pkey))
- cp->cert.siglen = htonl(len);
- zp = &cp->link;
- }
+ cp->cert.tstamp = hostval.tstamp;
+ cp->cert.siglen = 0;
+ if (cp->cert.sig == NULL)
+ cp->cert.sig = emalloc(sign_siglen);
+ EVP_SignInit(&ctx, sign_digest);
+ EVP_SignUpdate(&ctx, (u_char *)&cp->cert, 12);
+ EVP_SignUpdate(&ctx, cp->cert.ptr,
+ ntohl(cp->cert.vallen));
+ if (EVP_SignFinal(&ctx, cp->cert.sig, &len, sign_pkey))
+ cp->cert.siglen = htonl(len);
}
/*
@@ -1946,6 +2014,7 @@ asn2ntp (
*/
if (asn1time->length > 13)
return ((u_long)(~0)); /* We can't use -1 here. It's invalid */
+
v = (char *)asn1time->data;
tm.tm_year = (v[0] - '0') * 10 + v[1] - '0';
if (tm.tm_year < 50)
@@ -1983,6 +2052,9 @@ bighash(
EVP_DigestUpdate(&ctx, ptr, len);
EVP_DigestFinal(&ctx, dgst, &len);
BN_bin2bn(dgst, len, bk);
+
+ /* XXX MEMLEAK? free ptr? */
+
return (1);
}
@@ -2036,7 +2108,7 @@ bighash(
* Returns
* XEVNT_OK success
* XEVNT_PUB bad or missing public key
- * XEVNT_ID bad or missing identity parameters
+ * XEVNT_ID bad or missing group key
*/
static int
crypto_alice(
@@ -2055,6 +2127,7 @@ crypto_alice(
*/
if (peer->ident_pkey == NULL)
return (XEVNT_ID);
+
if ((dsa = peer->ident_pkey->pkey.dsa) == NULL) {
msyslog(LOG_INFO, "crypto_alice: defective key");
return (XEVNT_PUB);
@@ -2086,6 +2159,10 @@ crypto_alice(
vp->siglen = 0;
if (tstamp == 0)
return (XEVNT_OK);
+
+ if (tstamp < cinfo->first || tstamp > cinfo->last)
+ return (XEVNT_PER);
+
vp->sig = emalloc(sign_siglen);
EVP_SignInit(&ctx, sign_digest);
EVP_SignUpdate(&ctx, (u_char *)&vp->tstamp, 12);
@@ -2101,7 +2178,9 @@ crypto_alice(
*
* Returns
* XEVNT_OK success
- * XEVNT_PUB bad or missing public key
+ * XEVNT_ID bad or missing group key
+ * XEVNT_ERR protocol error
+ * XEVNT_PER host expired certificate
*/
static int
crypto_bob(
@@ -2122,9 +2201,9 @@ crypto_bob(
* If the IFF parameters are not valid, something awful
* happened or we are being tormented.
*/
- if (!(crypto_flags & CRYPTO_FLAG_IFF)) {
+ if (iffpar_pkey == NULL) {
msyslog(LOG_INFO, "crypto_bob: scheme unavailable");
- return (XEVNT_PUB);
+ return (XEVNT_ID);
}
dsa = iffpar_pkey->pkey.dsa;
@@ -2135,7 +2214,7 @@ crypto_bob(
if ((r = BN_bin2bn((u_char *)ep->pkt, len, NULL)) == NULL) {
msyslog(LOG_ERR, "crypto_bob %s\n",
ERR_error_string(ERR_get_error(), NULL));
- return (XEVNT_PUB);
+ return (XEVNT_ERR);
}
/*
@@ -2167,7 +2246,7 @@ crypto_bob(
msyslog(LOG_ERR, "crypto_bob %s\n",
ERR_error_string(ERR_get_error(), NULL));
DSA_SIG_free(sdsa);
- return (XEVNT_PUB);
+ return (XEVNT_ERR);
}
vp->vallen = htonl(len);
ptr = emalloc(len);
@@ -2177,6 +2256,10 @@ crypto_bob(
vp->siglen = 0;
if (tstamp == 0)
return (XEVNT_OK);
+
+ if (tstamp < cinfo->first || tstamp > cinfo->last)
+ return (XEVNT_PER);
+
vp->sig = emalloc(sign_siglen);
EVP_SignInit(&ctx, sign_digest);
EVP_SignUpdate(&ctx, (u_char *)&vp->tstamp, 12);
@@ -2193,8 +2276,8 @@ crypto_bob(
* Returns
* XEVNT_OK success
* XEVNT_PUB bad or missing public key
+ * XEVNT_ID bad or missing group key
* XEVNT_FSP bad filestamp
- * XEVNT_ID bad or missing identity parameters
*/
int
crypto_iff(
@@ -2216,7 +2299,7 @@ crypto_iff(
*/
if (peer->ident_pkey == NULL) {
msyslog(LOG_INFO, "crypto_iff: scheme unavailable");
- return (XEVNT_PUB);
+ return (XEVNT_ID);
}
if (ntohl(ep->fstamp) != peer->fstamp) {
msyslog(LOG_INFO, "crypto_iff: invalid filestamp %u",
@@ -2229,7 +2312,7 @@ crypto_iff(
}
if (peer->iffval == NULL) {
msyslog(LOG_INFO, "crypto_iff: missing challenge");
- return (XEVNT_PUB);
+ return (XEVNT_ID);
}
/*
@@ -2241,7 +2324,7 @@ crypto_iff(
if ((sdsa = d2i_DSA_SIG(NULL, &ptr, len)) == NULL) {
msyslog(LOG_ERR, "crypto_iff %s\n",
ERR_error_string(ERR_get_error(), NULL));
- return (XEVNT_PUB);
+ return (XEVNT_ERR);
}
/*
@@ -2262,6 +2345,7 @@ crypto_iff(
DSA_SIG_free(sdsa);
if (temp == 0)
return (XEVNT_OK);
+
else
return (XEVNT_ID);
}
@@ -2325,7 +2409,8 @@ crypto_iff(
* Returns
* XEVNT_OK success
* XEVNT_PUB bad or missing public key
- * XEVNT_ID bad or missing identity parameters
+ * XEVNT_ID bad or missing group key
+ * XEVNT_PER host certificate expired
*/
static int
crypto_alice2(
@@ -2344,6 +2429,7 @@ crypto_alice2(
*/
if (peer->ident_pkey == NULL)
return (XEVNT_ID);
+
if ((rsa = peer->ident_pkey->pkey.rsa) == NULL) {
msyslog(LOG_INFO, "crypto_alice2: defective key");
return (XEVNT_PUB);
@@ -2375,6 +2461,10 @@ crypto_alice2(
vp->siglen = 0;
if (tstamp == 0)
return (XEVNT_OK);
+
+ if (tstamp < cinfo->first || tstamp > cinfo->last)
+ return (XEVNT_PER);
+
vp->sig = emalloc(sign_siglen);
EVP_SignInit(&ctx, sign_digest);
EVP_SignUpdate(&ctx, (u_char *)&vp->tstamp, 12);
@@ -2390,7 +2480,9 @@ crypto_alice2(
*
* Returns
* XEVNT_OK success
- * XEVNT_PUB bad or missing public key
+ * XEVNT_ID bad or missing group key
+ * XEVNT_ERR protocol error
+ * XEVNT_PER host certificate expired
*/
static int
crypto_bob2(
@@ -2411,9 +2503,9 @@ crypto_bob2(
* If the GQ parameters are not valid, something awful
* happened or we are being tormented.
*/
- if (!(crypto_flags & CRYPTO_FLAG_GQ)) {
+ if (gqpar_pkey == NULL) {
msyslog(LOG_INFO, "crypto_bob2: scheme unavailable");
- return (XEVNT_PUB);
+ return (XEVNT_ID);
}
rsa = gqpar_pkey->pkey.rsa;
@@ -2424,7 +2516,7 @@ crypto_bob2(
if ((r = BN_bin2bn((u_char *)ep->pkt, len, NULL)) == NULL) {
msyslog(LOG_ERR, "crypto_bob2 %s\n",
ERR_error_string(ERR_get_error(), NULL));
- return (XEVNT_PUB);
+ return (XEVNT_ERR);
}
/*
@@ -2456,7 +2548,7 @@ crypto_bob2(
msyslog(LOG_ERR, "crypto_bob2 %s\n",
ERR_error_string(ERR_get_error(), NULL));
DSA_SIG_free(sdsa);
- return (XEVNT_PUB);
+ return (XEVNT_ERR);
}
vp->vallen = htonl(len);
ptr = emalloc(len);
@@ -2466,6 +2558,10 @@ crypto_bob2(
vp->siglen = 0;
if (tstamp == 0)
return (XEVNT_OK);
+
+ if (tstamp < cinfo->first || tstamp > cinfo->last)
+ return (XEVNT_PER);
+
vp->sig = emalloc(sign_siglen);
EVP_SignInit(&ctx, sign_digest);
EVP_SignUpdate(&ctx, (u_char *)&vp->tstamp, 12);
@@ -2482,8 +2578,9 @@ crypto_bob2(
* Returns
* XEVNT_OK success
* XEVNT_PUB bad or missing public key
+ * XEVNT_ID bad or missing group keys
+ * XEVNT_ERR protocol error
* XEVNT_FSP bad filestamp
- * XEVNT_ID bad or missing identity parameters
*/
int
crypto_gq(
@@ -2505,7 +2602,7 @@ crypto_gq(
*/
if (peer->ident_pkey == NULL) {
msyslog(LOG_INFO, "crypto_gq: scheme unavailable");
- return (XEVNT_PUB);
+ return (XEVNT_ID);
}
if (ntohl(ep->fstamp) != peer->fstamp) {
msyslog(LOG_INFO, "crypto_gq: invalid filestamp %u",
@@ -2518,7 +2615,7 @@ crypto_gq(
}
if (peer->iffval == NULL) {
msyslog(LOG_INFO, "crypto_gq: missing challenge");
- return (XEVNT_PUB);
+ return (XEVNT_ID);
}
/*
@@ -2531,7 +2628,7 @@ crypto_gq(
if ((sdsa = d2i_DSA_SIG(NULL, &ptr, len)) == NULL) {
msyslog(LOG_ERR, "crypto_gq %s\n",
ERR_error_string(ERR_get_error(), NULL));
- return (XEVNT_PUB);
+ return (XEVNT_ERR);
}
/*
@@ -2553,6 +2650,7 @@ crypto_gq(
DSA_SIG_free(sdsa);
if (temp == 0)
return (XEVNT_OK);
+
else
return (XEVNT_ID);
}
@@ -2637,7 +2735,8 @@ crypto_gq(
* Returns
* XEVNT_OK success
* XEVNT_PUB bad or missing public key
- * XEVNT_ID bad or missing identity parameters
+ * XEVNT_ID bad or missing group key
+ * XEVNT_PER host certificate expired
*/
static int
crypto_alice3(
@@ -2656,6 +2755,7 @@ crypto_alice3(
*/
if (peer->ident_pkey == NULL)
return (XEVNT_ID);
+
if ((dsa = peer->ident_pkey->pkey.dsa) == NULL) {
msyslog(LOG_INFO, "crypto_alice3: defective key");
return (XEVNT_PUB);
@@ -2687,6 +2787,10 @@ crypto_alice3(
vp->siglen = 0;
if (tstamp == 0)
return (XEVNT_OK);
+
+ if (tstamp < cinfo->first || tstamp > cinfo->last)
+ return (XEVNT_PER);
+
vp->sig = emalloc(sign_siglen);
EVP_SignInit(&ctx, sign_digest);
EVP_SignUpdate(&ctx, (u_char *)&vp->tstamp, 12);
@@ -2702,7 +2806,8 @@ crypto_alice3(
*
* Returns
* XEVNT_OK success
- * XEVNT_PUB bad or missing public key
+ * XEVNT_ERR protocol error
+ * XEVNT_PER host certificate expired
*/
static int
crypto_bob3(
@@ -2723,9 +2828,9 @@ crypto_bob3(
* If the MV parameters are not valid, something awful
* happened or we are being tormented.
*/
- if (!(crypto_flags & CRYPTO_FLAG_MV)) {
+ if (mvpar_pkey == NULL) {
msyslog(LOG_INFO, "crypto_bob3: scheme unavailable");
- return (XEVNT_PUB);
+ return (XEVNT_ID);
}
dsa = mvpar_pkey->pkey.dsa;
@@ -2736,7 +2841,7 @@ crypto_bob3(
if ((r = BN_bin2bn((u_char *)ep->pkt, len, NULL)) == NULL) {
msyslog(LOG_ERR, "crypto_bob3 %s\n",
ERR_error_string(ERR_get_error(), NULL));
- return (XEVNT_PUB);
+ return (XEVNT_ERR);
}
/*
@@ -2773,7 +2878,7 @@ crypto_bob3(
msyslog(LOG_ERR, "crypto_bob3 %s\n",
ERR_error_string(ERR_get_error(), NULL));
DSA_free(sdsa);
- return (XEVNT_PUB);
+ return (XEVNT_ERR);
}
vp->vallen = htonl(len);
ptr = emalloc(len);
@@ -2783,6 +2888,10 @@ crypto_bob3(
vp->siglen = 0;
if (tstamp == 0)
return (XEVNT_OK);
+
+ if (tstamp < cinfo->first || tstamp > cinfo->last)
+ return (XEVNT_PER);
+
vp->sig = emalloc(sign_siglen);
EVP_SignInit(&ctx, sign_digest);
EVP_SignUpdate(&ctx, (u_char *)&vp->tstamp, 12);
@@ -2799,8 +2908,9 @@ crypto_bob3(
* Returns
* XEVNT_OK success
* XEVNT_PUB bad or missing public key
+ * XEVNT_ID bad or missing group key
+ * XEVNT_ERR protocol error
* XEVNT_FSP bad filestamp
- * XEVNT_ID bad or missing identity parameters
*/
int
crypto_mv(
@@ -2822,7 +2932,7 @@ crypto_mv(
*/
if (peer->ident_pkey == NULL) {
msyslog(LOG_INFO, "crypto_mv: scheme unavailable");
- return (XEVNT_PUB);
+ return (XEVNT_ID);
}
if (ntohl(ep->fstamp) != peer->fstamp) {
msyslog(LOG_INFO, "crypto_mv: invalid filestamp %u",
@@ -2835,7 +2945,7 @@ crypto_mv(
}
if (peer->iffval == NULL) {
msyslog(LOG_INFO, "crypto_mv: missing challenge");
- return (XEVNT_PUB);
+ return (XEVNT_ID);
}
/*
@@ -2847,7 +2957,7 @@ crypto_mv(
if ((sdsa = d2i_DSAparams(NULL, &ptr, len)) == NULL) {
msyslog(LOG_ERR, "crypto_mv %s\n",
ERR_error_string(ERR_get_error(), NULL));
- return (XEVNT_PUB);
+ return (XEVNT_ERR);
}
/*
@@ -2870,6 +2980,7 @@ crypto_mv(
DSA_free(sdsa);
if (temp == 0)
return (XEVNT_OK);
+
else
return (XEVNT_ID);
}
@@ -3026,7 +3137,7 @@ cert_parse(
if (strcmp(ret->subject, ret->issuer) == 0) {
if (!X509_verify(cert, ret->pkey)) {
msyslog(LOG_INFO,
- "cert_parse: invalid signature not verified %s",
+ "cert_parse: signature not verified %s",
pathbuf);
cert_free(ret);
X509_free(cert);
@@ -3040,8 +3151,8 @@ cert_parse(
*/
if (ret->first > ret->last || ret->first < fstamp) {
msyslog(LOG_INFO,
- "cert_parse: expired %s",
- ret->subject);
+ "cert_parse: invalid certificate %s first %u last %u fstamp %u",
+ ret->subject, ret->first, ret->last, fstamp);
cert_free(ret);
X509_free(cert);
return (NULL);
@@ -3064,21 +3175,38 @@ cert_parse(
/*
- * cert_sign - sign x509 certificate and update value structure.
+ * cert_sign - sign x509 certificate equest and update value structure.
*
- * The certificate request is a copy of the client certificate, which
- * includes the version number, subject name and public key of the
- * client. The resulting certificate includes these values plus the
- * serial number, issuer name and validity interval of the server. The
- * validity interval extends from the current time to the same time one
- * year hence. For NTP purposes, it is convenient to use the NTP seconds
- * of the current time as the serial number.
+ * The certificate request includes a copy of the host certificate,
+ * which includes the version number, subject name and public key of the
+ * host. The resulting certificate includes these values plus the
+ * serial number, issuer name and valid interval of the server. The
+ * valid interval extends from the current time to the same time one
+ * year hence. This may extend the life of the signed certificate beyond
+ * that of the signer certificate.
+ *
+ * It is convenient to use the NTP seconds of the current time as the
+ * serial number. In the value structure the timestamp is the current
+ * time and the filestamp is taken from the extension field. Note this
+ * routine is called only when the client clock is synchronized to a
+ * proventic source, so timestamp comparisons are valid.
+ *
+ * The host certificate is valid from the time it was generated for a
+ * period of one year. A signed certificate is valid from the time of
+ * signature for a period of one year, but only the host certificate (or
+ * sign certificate if used) is actually used to encrypt and decrypt
+ * signatures. The signature trail is built from the client via the
+ * intermediate servers to the trusted server. Each signature on the
+ * trail must be valid at the time of signature, but it could happen
+ * that a signer certificate expire before the signed certificate, which
+ * remains valid until its expiration.
*
* Returns
* XEVNT_OK success
* XEVNT_PUB bad or missing public key
* XEVNT_CRT bad or missing certificate
* XEVNT_VFY certificate not verified
+ * XEVNT_PER host certificate expired
*/
static int
cert_sign(
@@ -3100,11 +3228,16 @@ cert_sign(
/*
* Decode ASN.1 objects and construct certificate structure.
+ * Make sure the system clock is synchronized to a proventic
+ * source.
*/
tstamp = crypto_time();
if (tstamp == 0)
return (XEVNT_TSP);
+ if (tstamp < cinfo->first || tstamp > cinfo->last)
+ return (XEVNT_PER);
+
ptr = (u_char *)ep->pkt;
if ((req = d2i_X509(NULL, &ptr, ntohl(ep->vallen))) == NULL) {
msyslog(LOG_ERR, "cert_sign %s\n",
@@ -3123,7 +3256,7 @@ cert_sign(
/*
* Generate X509 certificate signed by this server. For this
- * prupose the issuer name is the server name. Also copy any
+ * purpose the issuer name is the server name. Also copy any
* extensions that might be present.
*/
cert = X509_new();
@@ -3135,7 +3268,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,
- (unsigned char *) sys_hostname, strlen(sys_hostname), -1, 0);
+ (u_char *)sys_hostname, strlen(sys_hostname), -1, 0);
subj = X509_get_subject_name(req);
X509_set_subject_name(cert, subj);
X509_set_pubkey(cert, pkey);
@@ -3209,11 +3342,12 @@ cert_valid(
if (cinf->flags & CERT_SIGN)
return (XEVNT_OK);
+
ptr = (u_char *)cinf->cert.ptr;
cert = d2i_X509(NULL, &ptr, ntohl(cinf->cert.vallen));
- if (!X509_verify(cert, pkey))
+ if (cert == NULL || !X509_verify(cert, pkey))
return (XEVNT_VFY);
- cinf->flags |= CERT_SIGN;
+
X509_free(cert);
return (XEVNT_OK);
}
@@ -3230,7 +3364,7 @@ cert_valid(
*
* Returns
* XEVNT_OK success
- * XEVNT_PER certificate expired
+ * XEVNT_FSP bad or missing filestamp
* XEVNT_CRT bad or missing certificate
*/
int
@@ -3240,33 +3374,28 @@ cert_install(
)
{
struct cert_info *cp, *xp, *yp, **zp;
- int rval;
- tstamp_t tstamp;
/*
* Parse and validate the signed certificate. If valid,
* construct the info/value structure; otherwise, scamper home.
- * Note this allows a certificate not-before time to be in the
- * future, but not a not-after time to be in the past.
*/
if ((cp = cert_parse((u_char *)ep->pkt, ntohl(ep->vallen),
ntohl(ep->fstamp))) == NULL)
return (XEVNT_CRT);
- tstamp = crypto_time();
- if (tstamp > cp->last) {
- cert_free(cp);
- return (XEVNT_PER);
- }
-
/*
* Scan certificate list looking for another certificate with
* the same subject and issuer. If another is found with the
* same or older filestamp, unlink it and return the goodies to
- * the heap. If another is found with a later filetsamp, discard
+ * the heap. If another is found with a later filestamp, discard
* the new one and leave the building.
+ *
+ * Make a note to study this issue again. An earlier certificate
+ * with a long lifetime might be overtaken by a later
+ * certificate with a short lifetime, thus invalidating the
+ * earlier signature. However, we gotta find a way to leak old
+ * stuff from the cache, so we do it anyway.
*/
- rval = XEVNT_OK;
yp = cp;
zp = &cinfo;
for (xp = cinfo; xp != NULL; xp = xp->link) {
@@ -3278,7 +3407,7 @@ cert_install(
cert_free(xp);
} else {
cert_free(cp);
- return (XEVNT_TSP);
+ return (XEVNT_FSP);
}
break;
}
@@ -3288,29 +3417,42 @@ cert_install(
cinfo = yp;
/*
- * Scan the certificate list to see if Y is signed by X.
+ * Scan the certificate list to see if Y is signed by X. This is
+ * independent of order.
*/
for (yp = cinfo; yp != NULL; yp = yp->link) {
for (xp = cinfo; xp != NULL; xp = xp->link) {
- if (yp->flags & CERT_ERROR)
- continue;
/*
- * If issuer Y matches subject X and signature Y
- * is valid using public key X, then Y is valid.
+ * If the issuer of certificate Y matches the
+ * subject of certificate X, verify the
+ * signature of Y using the public key of X. If
+ * so, X signs Y.
*/
- if (strcmp(yp->issuer, xp->subject) != 0)
+ if (strcmp(yp->issuer, xp->subject) != 0 ||
+ xp->flags & CERT_ERROR)
continue;
if (cert_valid(yp, xp->pkey) != XEVNT_OK) {
yp->flags |= CERT_ERROR;
continue;
}
- xp->flags |= CERT_SIGN;
+
+ /*
+ * The signature Y is valid only if it begins
+ * during the lifetime of X; however, it is not
+ * necessarily an error, since some other
+ * certificate might sign Y.
+ */
+ if (yp->first < xp->first || yp->first >
+ xp->last)
+ continue;
+
+ yp->flags |= CERT_SIGN;
/*
* If X is trusted, then Y is trusted. Note that
- * we might stumble over a self signed
+ * we might stumble over a self-signed
* certificate that is not trusted, at least
* temporarily. This can happen when a dude
* first comes up, but has not synchronized the
@@ -3319,10 +3461,10 @@ cert_install(
* this might result in a loop that could
* persist until timeout.
*/
- if (!(xp->flags & CERT_TRUST))
+ if (!(xp->flags & (CERT_TRUST | CERT_VALID)))
continue;
- yp->flags |= CERT_TRUST;
+ yp->flags |= CERT_VALID;
/*
* If subject Y matches the server subject name,
@@ -3359,7 +3501,7 @@ cert_install(
* That was awesome. Now update the timestamps and signatures.
*/
crypto_update();
- return (rval);
+ return (XEVNT_OK);
}
@@ -3432,16 +3574,19 @@ crypto_key(
if ((ptr = fgets(linkname, MAXFILENAME, str)) == NULL) {
msyslog(LOG_ERR, "crypto_key: no data %s\n",
filename);
+ (void)fclose(str);
return (NULL);
}
if ((ptr = strrchr(ptr, '.')) == NULL) {
msyslog(LOG_ERR, "crypto_key: no filestamp %s\n",
filename);
+ (void)fclose(str);
return (NULL);
}
if (sscanf(++ptr, "%u", fstamp) != 1) {
msyslog(LOG_ERR, "crypto_key: invalid timestamp %s\n",
filename);
+ (void)fclose(str);
return (NULL);
}
@@ -3523,16 +3668,19 @@ crypto_cert(
if ((ptr = fgets(linkname, MAXFILENAME, str)) == NULL) {
msyslog(LOG_ERR, "crypto_cert: no data %s\n",
filename);
+ (void)fclose(str);
return (NULL);
}
if ((ptr = strrchr(ptr, '.')) == NULL) {
msyslog(LOG_ERR, "crypto_cert: no filestamp %s\n",
filename);
+ (void)fclose(str);
return (NULL);
}
if (sscanf(++ptr, "%u", &fstamp) != 1) {
msyslog(LOG_ERR, "crypto_cert: invalid filestamp %s\n",
filename);
+ (void)fclose(str);
return (NULL);
}
@@ -3542,6 +3690,7 @@ crypto_cert(
if (!PEM_read(str, &name, &header, &data, &len)) {
msyslog(LOG_ERR, "crypto_cert %s\n",
ERR_error_string(ERR_get_error(), NULL));
+ (void)fclose(str);
return (NULL);
}
free(header);
@@ -3550,6 +3699,7 @@ crypto_cert(
name);
free(name);
free(data);
+ (void)fclose(str);
return (NULL);
}
free(name);
@@ -3559,8 +3709,10 @@ crypto_cert(
*/
ret = cert_parse(data, len, fstamp);
free(data);
+ (void)fclose(str);
if (ret == NULL)
return (NULL);
+
if ((ptr = strrchr(linkname, '\n')) != NULL)
*ptr = '\0';
sprintf(statstr, "%s 0x%x len %lu", &linkname[2], ret->flags,
@@ -3590,20 +3742,16 @@ crypto_tai(
{
FILE *str; /* file handle */
char buf[NTP_MAXSTRLEN]; /* file line buffer */
- u_int leapsec[MAX_LEAP]; /* NTP time at leaps */
- u_int offset; /* offset at leap (s) */
+ u_int32 leapsec[MAX_LEAP]; /* NTP time at leaps */
+ int offset; /* offset at leap (s) */
char filename[MAXFILENAME]; /* name of leapseconds file */
char linkname[MAXFILENAME]; /* file link (for filestamp) */
char statstr[NTP_MAXSTRLEN]; /* statistics for filegen */
tstamp_t fstamp; /* filestamp */
u_int len;
- char *ptr;
- int rval, i;
-#ifdef KERNEL_PLL
-#if NTP_API > 3
- struct timex ntv; /* kernel interface structure */
-#endif /* NTP_API */
-#endif /* KERNEL_PLL */
+ u_int32 *ptr;
+ char *dp;
+ int rval, i, j;
/*
* Open the file and discard comment lines. If the first
@@ -3625,12 +3773,12 @@ crypto_tai(
rval = readlink(filename, linkname, MAXFILENAME - 1);
if (rval > 0) {
linkname[rval] = '\0';
- ptr = strrchr(linkname, '.');
+ dp = strrchr(linkname, '.');
} else {
- ptr = strrchr(filename, '.');
+ dp = strrchr(filename, '.');
}
- if (ptr != NULL)
- sscanf(++ptr, "%u", &fstamp);
+ if (dp != NULL)
+ sscanf(++dp, "%u", &fstamp);
else
fstamp = 0;
tai_leap.fstamp = htonl(fstamp);
@@ -3647,22 +3795,26 @@ crypto_tai(
*/
i = 0;
while (i < MAX_LEAP) {
- ptr = fgets(buf, NTP_MAXSTRLEN - 1, str);
- if (ptr == NULL)
+ dp = fgets(buf, NTP_MAXSTRLEN - 1, str);
+ if (dp == NULL)
break;
+
if (strlen(buf) < 1)
continue;
+
if (*buf == '#')
continue;
- if (sscanf(buf, "%u %u", &leapsec[i], &offset) != 2)
+
+ if (sscanf(buf, "%u %d", &leapsec[i], &offset) != 2)
continue;
- if (i != (int)(offset - TAI_1972)) {
+
+ if (i != offset - TAI_1972)
break;
- }
+
i++;
}
fclose(str);
- if (ptr != NULL) {
+ if (dp != NULL) {
msyslog(LOG_INFO,
"crypto_tai: leapseconds file %s error %d", cp,
rval);
@@ -3671,29 +3823,17 @@ crypto_tai(
/*
* The extension field table entries consists of the NTP seconds
- * of leap insertion in reverse order, so that the most recent
- * insertion is the first entry in the table.
+ * of leap insertion in network byte order.
*/
- len = i * 4;
+ len = i * sizeof(u_int32);
tai_leap.vallen = htonl(len);
ptr = emalloc(len);
- tai_leap.ptr = (unsigned char *) ptr;
- for (; i >= 0; i--) {
- *ptr++ = (char) htonl(leapsec[i]);
- }
+ tai_leap.ptr = (u_char *)ptr;
+ for (j = 0; j < i; j++)
+ *ptr++ = htonl(leapsec[j]);
crypto_flags |= CRYPTO_FLAG_TAI;
- sys_tai = len / 4 + TAI_1972 - 1;
-#ifdef KERNEL_PLL
-#if NTP_API > 3
- ntv.modes = MOD_TAI;
- ntv.constant = sys_tai;
- if (ntp_adjtime(&ntv) == TIME_ERROR)
- msyslog(LOG_INFO,
- "crypto_tai: kernel TAI update failed");
-#endif /* NTP_API */
-#endif /* KERNEL_PLL */
- sprintf(statstr, "%s link %d fs %u offset %u", cp, rval, fstamp,
- ntohl(tai_leap.vallen) / 4 + TAI_1972 - 1);
+ sprintf(statstr, "%s fs %u leap %u len %u", cp, fstamp,
+ leapsec[--j], len);
record_crypto_stats(NULL, statstr);
#ifdef DEBUG
if (debug)
@@ -3727,6 +3867,7 @@ crypto_setup(void)
*/
if (!crypto_flags)
return;
+
gethostname(filename, MAXFILENAME);
bytes = strlen(filename) + 1;
sys_hostname = emalloc(bytes);
@@ -3806,7 +3947,7 @@ crypto_setup(void)
exit (-1);
}
hostval.vallen = htonl(strlen(sys_hostname));
- hostval.ptr = (unsigned char *) sys_hostname;
+ hostval.ptr = (u_char *)sys_hostname;
/*
* Construct public key extension field for agreement scheme.
@@ -3909,7 +4050,7 @@ crypto_setup(void)
* It the certificate is trusted, the subject must be the same
* as the issuer, in other words it must be self signed.
*/
- if (cinfo->flags & CERT_PRIV && strcmp(cinfo->subject,
+ if (cinfo->flags & CERT_TRUST && strcmp(cinfo->subject,
cinfo->issuer) != 0) {
if (cert_valid(cinfo, sign_pkey) != XEVNT_OK) {
msyslog(LOG_ERR,
@@ -4009,6 +4150,18 @@ crypto_config(
break;
/*
+ * Set identity scheme.
+ */
+ case CRYPTO_CONF_IDENT:
+ if (!strcasecmp(cp, "iff"))
+ ident_scheme |= CRYPTO_FLAG_IFF;
+ else if (!strcasecmp(cp, "gq"))
+ ident_scheme |= CRYPTO_FLAG_GQ;
+ else if (!strcasecmp(cp, "mv"))
+ ident_scheme |= CRYPTO_FLAG_MV;
+ break;
+
+ /*
* Set certificate file name.
*/
case CRYPTO_CONF_CERT:
OpenPOWER on IntegriCloud