/* * keytype_from_text returns OpenSSL NID for digest by name, and * optionally the associated digest length. * * Used by ntpd authreadkeys(), ntpq keytype() */ int keytype_from_text( const char *text, size_t *pdigest_len ) { int key_type; u_int digest_len; #ifdef HAVE_OPENSSL const u_long max_digest_len = MAX_MAC_LEN - sizeof(keyid_t); uint8_t digest[EVP_MAX_MD_SIZE]; char * upcased; char * pch; EVP_MD_CTX ctx; /* * OpenSSL digest short names are capitalized, so uppercase the * digest name before passing to OBJ_sn2nid(). If it is not * recognized but begins with 'M' use NID_md5 to be consistent * with past behavior. */ INIT_SSL(); LIB_GETBUF(upcased); strlcpy(upcased, text, LIB_BUFLENGTH); for (pch = upcased; '\0' != *pch; pch++) *pch = (char)toupper((unsigned char)*pch); key_type = OBJ_sn2nid(upcased); #else key_type = 0; #endif if (!key_type && 'm' == tolower((unsigned char)text[0])) key_type = NID_md5; if (!key_type) return 0; if (NULL != pdigest_len) { #ifdef HAVE_OPENSSL EVP_DigestInit(&ctx, EVP_get_digestbynid(key_type)); EVP_DigestFinal(&ctx, digest, &digest_len); if (digest_len > max_digest_len) { fprintf(stderr, "key type %s %u octet digests are too big, max %lu\n", keytype_name(key_type), digest_len, max_digest_len); msyslog(LOG_ERR, "key type %s %u octet digests are too big, max %lu", keytype_name(key_type), digest_len, max_digest_len); return 0; } #else digest_len = 16; #endif *pdigest_len = digest_len; } return key_type; }
void test_SHA1KeyName() { #ifdef OPENSSL TEST_ASSERT_EQUAL_STRING("SHA", keytype_name(NID_sha)); #else TEST_IGNORE_MESSAGE("Skipping because OPENSSL isn't defined"); #endif /* OPENSSL */ }
/* * keytype - get type of key to use for authenticating requests */ static void keytype( struct parse *pcmd, FILE *fp ) { const char * digest_name; size_t digest_len; int key_type; if (!pcmd->nargs) { fprintf(fp, "keytype is %s with %lu octet digests\n", keytype_name(info_auth_keytype), (u_long)info_auth_hashlen); return; } digest_name = pcmd->argval[0].string; digest_len = 0; key_type = keytype_from_text(digest_name, &digest_len); if (!key_type) { fprintf(fp, "keytype must be 'md5'%s\n", #ifdef OPENSSL " or a digest type provided by OpenSSL"); #else ""); #endif return; }
/* * getpass_keytype() -- shared between ntpq and ntpdc, only vaguely * related to the rest of ssl_init.c. */ char * getpass_keytype( int keytype ) { char pass_prompt[64 + 11 + 1]; /* 11 for " Password: "******"%.64s Password: ", keytype_name(keytype)); return getpass(pass_prompt); }
TEST(ssl_init, SHA1KeyName) { TEST_ASSERT_EQUAL_STRING("SHA", keytype_name(NID_sha)); }
// keytype_name() TEST(ssl_init, MD5KeyName) { TEST_ASSERT_EQUAL_STRING("MD5", keytype_name(KEY_TYPE_MD5)); }
// keytype_name() void test_MD5KeyName() { TEST_ASSERT_EQUAL_STRING("MD5", keytype_name(KEY_TYPE_MD5)); }
TEST_F(ssl_initTest, SHA1KeyName) { EXPECT_STREQ("SHA", keytype_name(NID_sha)); }
// keytype_name() TEST_F(ssl_initTest, MD5KeyName) { EXPECT_STREQ("MD5", keytype_name(KEY_TYPE_MD5)); }
/* * sendrequest - format and send a request packet * * Historically, ntpdc has used a fixed-size request packet regardless * of the actual payload size. When authenticating, the timestamp, key * ID, and digest have been placed just before the end of the packet. * With the introduction in late 2009 of support for authenticated * ntpdc requests using larger 20-octet digests (vs. 16 for MD5), we * come up four bytes short. * * To maintain interop while allowing for larger digests, the behavior * is unchanged when using 16-octet digests. For larger digests, the * timestamp, key ID, and digest are placed immediately following the * request payload, with the overall packet size variable. ntpd can * distinguish 16-octet digests by the overall request size being * REQ_LEN_NOMAC + 4 + 16 with the auth bit enabled. When using a * longer digest, that request size should be avoided. * * With the form used with 20-octet and larger digests, the timestamp, * key ID, and digest are located by ntpd relative to the start of the * packet, and the size of the digest is then implied by the packet * size. */ static int sendrequest( int implcode, int reqcode, int auth, u_int qitems, size_t qsize, char *qdata ) { struct req_pkt qpkt; size_t datasize; size_t reqsize; u_long key_id; l_fp ts; l_fp * ptstamp; int maclen; char pass_prompt[32]; char * pass; memset(&qpkt, 0, sizeof(qpkt)); qpkt.rm_vn_mode = RM_VN_MODE(0, 0, 0); qpkt.implementation = (u_char)implcode; qpkt.request = (u_char)reqcode; datasize = qitems * qsize; if (datasize && qdata != NULL) { memcpy(qpkt.data, qdata, datasize); qpkt.err_nitems = ERR_NITEMS(0, qitems); qpkt.mbz_itemsize = MBZ_ITEMSIZE(qsize); } else { qpkt.err_nitems = ERR_NITEMS(0, 0); qpkt.mbz_itemsize = MBZ_ITEMSIZE(qsize); /* allow for optional first item */ } if (!auth || (keyid_entered && info_auth_keyid == 0)) { qpkt.auth_seq = AUTH_SEQ(0, 0); return sendpkt(&qpkt, req_pkt_size); } if (info_auth_keyid == 0) { key_id = getkeyid("Keyid: "); if (!key_id) { fprintf(stderr, "Invalid key identifier\n"); return 1; } info_auth_keyid = key_id; } if (!authistrusted(info_auth_keyid)) { snprintf(pass_prompt, sizeof(pass_prompt), "%s Password: "******"Invalid password\n"); return 1; } authusekey(info_auth_keyid, info_auth_keytype, (u_char *)pass); authtrust(info_auth_keyid, 1); } qpkt.auth_seq = AUTH_SEQ(1, 0); if (info_auth_hashlen > 16) { /* * Only ntpd which expects REQ_LEN_NOMAC plus maclen * octets in an authenticated request using a 16 octet * digest (that is, a newer ntpd) will handle digests * larger than 16 octets, so for longer digests, do * not attempt to shorten the requests for downlevel * ntpd compatibility. */ if (REQ_LEN_NOMAC != req_pkt_size) return 1; reqsize = REQ_LEN_HDR + datasize + sizeof(*ptstamp); /* align to 32 bits */ reqsize = (reqsize + 3) & ~3; } else reqsize = req_pkt_size; ptstamp = (void *)((char *)&qpkt + reqsize); ptstamp--; get_systime(&ts); L_ADD(&ts, &delay_time); HTONL_FP(&ts, ptstamp); maclen = authencrypt(info_auth_keyid, (void *)&qpkt, reqsize); if (!maclen) { fprintf(stderr, "Key not found\n"); return 1; } else if (maclen != (info_auth_hashlen + sizeof(keyid_t))) { fprintf(stderr, "%d octet MAC, %u expected with %u octet digest\n", maclen, (info_auth_hashlen + sizeof(keyid_t)), info_auth_hashlen); return 1; } return sendpkt(&qpkt, reqsize + maclen); }