TEST(ssl_init, SHA1KeyTypeWithDigestLength) { size_t digestLength; size_t expected = TEST_SHA1_DIGEST_LENGTH; TEST_ASSERT_EQUAL(NID_sha, keytype_from_text("SHA", &digestLength)); TEST_ASSERT_EQUAL(expected, digestLength); }
void test_VerifySHA1(void) { #ifdef OPENSSL const char* PKT_DATA = "sometestdata" /* Data */ "\0\0\0\0" /* Key-ID (unused) */ "\xad\x07\xde\x36\x39\xa6\x77\xfa\x5b\xce" /* MAC */ "\x2d\x8a\x7d\x06\x96\xe6\x0c\xbc\xed\xe1"; const int PKT_LEN = 12; struct key sha1; sha1.next = NULL; sha1.key_id = 0; sha1.key_len = 7; memcpy(&sha1.key_seq, "sha1key", sha1.key_len); strlcpy(sha1.typen, "SHA1", sizeof(sha1.typen)); sha1.typei = keytype_from_text(sha1.typen, NULL); TEST_ASSERT_TRUE(auth_md5(PKT_DATA, PKT_LEN, SHA1_LENGTH, &sha1)); #else TEST_IGNORE_MESSAGE("OpenSSL not found, skipping..."); #endif /* OPENSSL */ }
TEST(ssl_init, MD5KeyTypeWithDigestLength) { size_t digestLength; size_t expected = TEST_MD5_DIGEST_LENGTH; TEST_ASSERT_EQUAL(KEY_TYPE_MD5, keytype_from_text("MD5", &digestLength)); TEST_ASSERT_EQUAL(expected, digestLength); }
TEST_F(ssl_initTest, MD5KeyTypeWithDigestLength) { size_t digestLength; size_t expected = TEST_MD5_DIGEST_LENGTH; EXPECT_EQ(KEY_TYPE_MD5, keytype_from_text("MD5", &digestLength)); EXPECT_EQ(expected, digestLength); }
TEST_F(ssl_initTest, SHA1KeyTypeWithDigestLength) { size_t digestLength; size_t expected = TEST_SHA1_DIGEST_LENGTH; EXPECT_EQ(NID_sha, keytype_from_text("SHA", &digestLength)); EXPECT_EQ(expected, digestLength); }
void test_MakeSHA1Mac(void) { #ifdef OPENSSL const char* PKT_DATA = "abcdefgh0123"; const int PKT_LEN = strlen(PKT_DATA); const char* EXPECTED_DIGEST = "\x17\xaa\x82\x97\xc7\x17\x13\x6a\x9b\xa9" "\x63\x85\xb4\xce\xbe\x94\xa0\x97\x16\x1d"; char actual[SHA1_LENGTH]; struct key sha1; sha1.next = NULL; sha1.key_id = 20; sha1.key_len = 7; memcpy(&sha1.key_seq, "sha1seq", sha1.key_len); strlcpy(sha1.typen, "SHA1", sizeof(sha1.typen)); sha1.typei = keytype_from_text(sha1.typen, NULL); TEST_ASSERT_EQUAL(SHA1_LENGTH, make_mac(PKT_DATA, PKT_LEN, SHA1_LENGTH, &sha1, actual)); TEST_ASSERT_EQUAL_MEMORY(EXPECTED_DIGEST, actual, SHA1_LENGTH); #else TEST_IGNORE_MESSAGE("OpenSSL not found, skipping..."); #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; }
void test_SHA1KeyTypeWithDigestLength() { #ifdef OPENSSL size_t digestLength; size_t expected = TEST_SHA1_DIGEST_LENGTH; TEST_ASSERT_EQUAL(NID_sha, keytype_from_text("SHA", &digestLength)); TEST_ASSERT_EQUAL(expected, digestLength); /* OPENSSL */ #else TEST_IGNORE_MESSAGE("Skipping because OPENSSL isn't defined"); #endif }
void test_PacketSizeNotMultipleOfFourBytes(void) { const char* PKT_DATA = "123456"; const int PKT_LEN = 6; char actual[MD5_LENGTH]; struct key md5; md5.next = NULL; md5.key_id = 10; md5.key_len = 6; memcpy(&md5.key_seq, "md5seq", md5.key_len); strlcpy(md5.typen, "MD5", sizeof(md5.typen)); md5.typei = keytype_from_text(md5.typen, NULL); TEST_ASSERT_EQUAL(0, make_mac(PKT_DATA, PKT_LEN, MD5_LENGTH, &md5, actual)); }
void test_VerifyCorrectMD5(void) { const char* PKT_DATA = "sometestdata" /* Data */ "\0\0\0\0" /* Key-ID (unused) */ "\xc7\x58\x99\xdd\x99\x32\x0f\x71" /* MAC */ "\x2b\x7b\xfe\x4f\xa2\x32\xcf\xac"; const int PKT_LEN = 12; struct key md5; md5.next = NULL; md5.key_id = 0; md5.key_len = 6; memcpy(&md5.key_seq, "md5key", md5.key_len); strlcpy(md5.typen, "MD5", sizeof(md5.typen)); md5.typei = keytype_from_text(md5.typen, NULL); TEST_ASSERT_TRUE(auth_md5(PKT_DATA, PKT_LEN, MD5_LENGTH, &md5)); }
void test_GenerateAuthenticatedPacket(void) { static const int EXPECTED_PKTLEN = LEN_PKT_NOMAC + MAX_MD5_LEN; struct key testkey; struct pkt testpkt; struct timeval xmt; l_fp expected_xmt, actual_xmt; char expected_mac[MAX_MD5_LEN]; testkey.next = NULL; testkey.key_id = 30; testkey.key_len = 9; memcpy(testkey.key_seq, "123456789", testkey.key_len); strlcpy(testkey.typen, "MD5", sizeof(testkey.typen)); testkey.typei = keytype_from_text(testkey.typen, NULL); GETTIMEOFDAY(&xmt, NULL); xmt.tv_sec += JAN_1970; TEST_ASSERT_EQUAL(EXPECTED_PKTLEN, generate_pkt(&testpkt, &xmt, testkey.key_id, &testkey)); TEST_ASSERT_EQUAL(LEAP_NOTINSYNC, PKT_LEAP(testpkt.li_vn_mode)); TEST_ASSERT_EQUAL(NTP_VERSION, PKT_VERSION(testpkt.li_vn_mode)); TEST_ASSERT_EQUAL(MODE_CLIENT, PKT_MODE(testpkt.li_vn_mode)); TEST_ASSERT_EQUAL(STRATUM_UNSPEC, PKT_TO_STRATUM(testpkt.stratum)); TEST_ASSERT_EQUAL(8, testpkt.ppoll); TVTOTS(&xmt, &expected_xmt); NTOHL_FP(&testpkt.xmt, &actual_xmt); TEST_ASSERT_TRUE(LfpEquality(expected_xmt, actual_xmt)); TEST_ASSERT_EQUAL(testkey.key_id, ntohl(testpkt.exten[0])); TEST_ASSERT_EQUAL(MAX_MD5_LEN - 4, /* Remove the key_id, only keep the mac. */ make_mac(&testpkt, LEN_PKT_NOMAC, MAX_MD5_LEN-4, &testkey, expected_mac)); TEST_ASSERT_EQUAL_MEMORY(expected_mac, (char*)&testpkt.exten[1], MAX_MD5_LEN -4); }
void test_MakeMd5Mac(void) { const char* PKT_DATA = "abcdefgh0123"; const int PKT_LEN = strlen(PKT_DATA); const char* EXPECTED_DIGEST = "\x52\x6c\xb8\x38\xaf\x06\x5a\xfb\x6c\x98\xbb\xc0\x9b\x0a\x7a\x1b"; char actual[MD5_LENGTH]; struct key md5; md5.next = NULL; md5.key_id = 10; md5.key_len = 6; memcpy(&md5.key_seq, "md5seq", md5.key_len); strlcpy(md5.typen, "MD5", sizeof(md5.typen)); md5.typei = keytype_from_text(md5.typen, NULL); TEST_ASSERT_EQUAL(MD5_LENGTH, make_mac(PKT_DATA, PKT_LEN, MD5_LENGTH, &md5, actual)); TEST_ASSERT_TRUE(memcmp(EXPECTED_DIGEST, actual, MD5_LENGTH) == 0); }
void test_VerifyFailure(void) { /* We use a copy of the MD5 verification code, but modify the * last bit to make sure verification fails. */ const char* PKT_DATA = "sometestdata" /* Data */ "\0\0\0\0" /* Key-ID (unused) */ "\xc7\x58\x99\xdd\x99\x32\x0f\x71" /* MAC */ "\x2b\x7b\xfe\x4f\xa2\x32\xcf\x00"; /* Last byte is wrong! */ const int PKT_LEN = 12; struct key md5; md5.next = NULL; md5.key_id = 0; md5.key_len = 6; memcpy(&md5.key_seq, "md5key", md5.key_len); strlcpy(md5.typen, "MD5", sizeof(md5.typen)); md5.typei = keytype_from_text(md5.typen, NULL); TEST_ASSERT_FALSE(auth_md5(PKT_DATA, PKT_LEN, MD5_LENGTH, &md5)); }
// keytype_from_text() TEST(ssl_init, MD5KeyTypeWithoutDigestLength) { TEST_ASSERT_EQUAL(KEY_TYPE_MD5, keytype_from_text("MD5", NULL)); }
/* * authreadkeys - (re)read keys from a file. */ int authreadkeys( const char *file ) { FILE *fp; char *line; char *token; keyid_t keyno; int keytype; char buf[512]; /* lots of room for line */ u_char keystr[20]; size_t len; size_t j; /* * Open file. Complain and return if it can't be opened. */ fp = fopen(file, "r"); if (fp == NULL) { msyslog(LOG_ERR, "authreadkeys: file %s: %m", file); return (0); } INIT_SSL(); /* * Remove all existing keys */ auth_delkeys(); /* * Now read lines from the file, looking for key entries */ while ((line = fgets(buf, sizeof buf, fp)) != NULL) { token = nexttok(&line); if (token == NULL) continue; /* * First is key number. See if it is okay. */ keyno = atoi(token); if (keyno == 0) { msyslog(LOG_ERR, "authreadkeys: cannot change key %s", token); continue; } if (keyno > NTP_MAXKEY) { msyslog(LOG_ERR, "authreadkeys: key %s > %d reserved for Autokey", token, NTP_MAXKEY); continue; } /* * Next is keytype. See if that is all right. */ token = nexttok(&line); if (token == NULL) { msyslog(LOG_ERR, "authreadkeys: no key type for key %d", keyno); continue; } #ifdef OPENSSL /* * The key type is the NID used by the message digest * algorithm. There are a number of inconsistencies in * the OpenSSL database. We attempt to discover them * here and prevent use of inconsistent data later. */ keytype = keytype_from_text(token, NULL); if (keytype == 0) { msyslog(LOG_ERR, "authreadkeys: invalid type for key %d", keyno); continue; } if (EVP_get_digestbynid(keytype) == NULL) { msyslog(LOG_ERR, "authreadkeys: no algorithm for key %d", keyno); continue; } #else /* !OPENSSL follows */ /* * The key type is unused, but is required to be 'M' or * 'm' for compatibility. */ if (!(*token == 'M' || *token == 'm')) { msyslog(LOG_ERR, "authreadkeys: invalid type for key %d", keyno); continue; } keytype = KEY_TYPE_MD5; #endif /* !OPENSSL */ /* * Finally, get key and insert it. If it is longer than 20 * characters, it is a binary string encoded in hex; * otherwise, it is a text string of printable ASCII * characters. */ token = nexttok(&line); if (token == NULL) { msyslog(LOG_ERR, "authreadkeys: no key for key %d", keyno); continue; } len = strlen(token); if (len <= sizeof(keystr)) { MD5auth_setkey(keyno, keytype, (u_char *)token, len); } else { char hex[] = "0123456789abcdef"; u_char temp; char *ptr; size_t jlim; jlim = min(len, 2 * sizeof(keystr)); for (j = 0; j < jlim; j++) { ptr = strchr(hex, tolower((unsigned char)token[j])); if (ptr == NULL) break; /* abort decoding */ temp = (u_char)(ptr - hex); if (j & 1) keystr[j / 2] |= temp; else keystr[j / 2] = temp << 4; } if (j < jlim) { msyslog(LOG_ERR, "authreadkeys: invalid hex digit for key %d", keyno); continue; } MD5auth_setkey(keyno, keytype, keystr, jlim / 2); } } fclose(fp); return (1); }
// keytype_from_text() TEST_F(ssl_initTest, MD5KeyTypeWithoutDigestLength) { ASSERT_EQ(KEY_TYPE_MD5, keytype_from_text("MD5", NULL)); }
/* * authreadkeys - (re)read keys from a file. */ int authreadkeys( const char *file ) { FILE *fp; char *line; char *token; keyid_t keyno; int keytype; char buf[512]; /* lots of room for line */ u_char keystr[32]; /* Bug 2537 */ size_t len; size_t j; u_int nerr; KeyDataT *list = NULL; KeyDataT *next = NULL; /* * Open file. Complain and return if it can't be opened. */ fp = fopen(file, "r"); if (fp == NULL) { msyslog(LOG_ERR, "authreadkeys: file '%s': %m", file); goto onerror; } INIT_SSL(); /* * Now read lines from the file, looking for key entries. Put * the data into temporary store for later propagation to avoid * two-pass processing. */ nerr = 0; while ((line = fgets(buf, sizeof buf, fp)) != NULL) { if (nerr > nerr_maxlimit) break; token = nexttok(&line); if (token == NULL) continue; /* * First is key number. See if it is okay. */ keyno = atoi(token); if (keyno == 0) { log_maybe(&nerr, "authreadkeys: cannot change key %s", token); continue; } if (keyno > NTP_MAXKEY) { log_maybe(&nerr, "authreadkeys: key %s > %d reserved for Autokey", token, NTP_MAXKEY); continue; } /* * Next is keytype. See if that is all right. */ token = nexttok(&line); if (token == NULL) { log_maybe(&nerr, "authreadkeys: no key type for key %d", keyno); continue; } #ifdef OPENSSL /* * The key type is the NID used by the message digest * algorithm. There are a number of inconsistencies in * the OpenSSL database. We attempt to discover them * here and prevent use of inconsistent data later. */ keytype = keytype_from_text(token, NULL); if (keytype == 0) { log_maybe(&nerr, "authreadkeys: invalid type for key %d", keyno); continue; } if (EVP_get_digestbynid(keytype) == NULL) { log_maybe(&nerr, "authreadkeys: no algorithm for key %d", keyno); continue; } #else /* !OPENSSL follows */ /* * The key type is unused, but is required to be 'M' or * 'm' for compatibility. */ if (!(*token == 'M' || *token == 'm')) { log_maybe(&nerr, "authreadkeys: invalid type for key %d", keyno); continue; } keytype = KEY_TYPE_MD5; #endif /* !OPENSSL */ /* * Finally, get key and insert it. If it is longer than 20 * characters, it is a binary string encoded in hex; * otherwise, it is a text string of printable ASCII * characters. */ token = nexttok(&line); if (token == NULL) { log_maybe(&nerr, "authreadkeys: no key for key %d", keyno); continue; } next = NULL; len = strlen(token); if (len <= 20) { /* Bug 2537 */ next = emalloc(sizeof(KeyDataT) + len); next->keyacclist = NULL; next->keyid = keyno; next->keytype = keytype; next->seclen = len; memcpy(next->secbuf, token, len); } else { static const char hex[] = "0123456789abcdef"; u_char temp; char *ptr; size_t jlim; jlim = min(len, 2 * sizeof(keystr)); for (j = 0; j < jlim; j++) { ptr = strchr(hex, tolower((unsigned char)token[j])); if (ptr == NULL) break; /* abort decoding */ temp = (u_char)(ptr - hex); if (j & 1) keystr[j / 2] |= temp; else keystr[j / 2] = temp << 4; } if (j < jlim) { log_maybe(&nerr, "authreadkeys: invalid hex digit for key %d", keyno); continue; } len = jlim/2; /* hmmmm.... what about odd length?!? */ next = emalloc(sizeof(KeyDataT) + len); next->keyacclist = NULL; next->keyid = keyno; next->keytype = keytype; next->seclen = len; memcpy(next->secbuf, keystr, len); } token = nexttok(&line); DPRINTF(0, ("authreadkeys: full access list <%s>\n", (token) ? token : "NULL")); if (token != NULL) { /* A comma-separated IP access list */ char *tp = token; while (tp) { char *i; KeyAccT ka; i = strchr(tp, (int)','); if (i) *i = '\0'; DPRINTF(0, ("authreadkeys: access list: <%s>\n", tp)); if (is_ip_address(tp, AF_UNSPEC, &ka.addr)) { KeyAccT *kap; kap = emalloc(sizeof(KeyAccT)); memcpy(kap, &ka, sizeof ka); kap->next = next->keyacclist; next->keyacclist = kap; } else { log_maybe(&nerr, "authreadkeys: invalid IP address <%s> for key %d", tp, keyno); } if (i) { tp = i + 1; } else { tp = 0; } } } INSIST(NULL != next); next->next = list; list = next; } fclose(fp); if (nerr > nerr_maxlimit) { msyslog(LOG_ERR, "authreadkeys: rejecting file '%s' after %u errors (emergency break)", file, nerr); goto onerror; } if (nerr > 0) { msyslog(LOG_ERR, "authreadkeys: rejecting file '%s' after %u error(s)", file, nerr); goto onerror; } /* first remove old file-based keys */ auth_delkeys(); /* insert the new key material */ while (NULL != (next = list)) { list = next->next; MD5auth_setkey(next->keyid, next->keytype, next->secbuf, next->seclen, next->keyacclist); /* purge secrets from memory before free()ing it */ memset(next, 0, sizeof(*next) + next->seclen); free(next); } return (1); onerror: /* Mop up temporary storage before bailing out. */ while (NULL != (next = list)) { list = next->next; while (next->keyacclist) { KeyAccT *kap = next->keyacclist; next->keyacclist = kap->next; free(kap); } /* purge secrets from memory before free()ing it */ memset(next, 0, sizeof(*next) + next->seclen); free(next); } return (0); }
// keytype_from_text() void test_MD5KeyTypeWithoutDigestLength() { TEST_ASSERT_EQUAL(KEY_TYPE_MD5, keytype_from_text("MD5", NULL)); }