File: pymodule-mac.c

package info (click to toggle)
ntpsec 1.2.4%2Bdfsg-1
  • links: PTS, VCS
  • area: main
  • in suites: sid
  • size: 10,360 kB
  • sloc: ansic: 62,698; python: 32,477; sh: 1,575; yacc: 1,331; makefile: 193; javascript: 138
file content (165 lines) | stat: -rw-r--r-- 3,969 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
/*
 * Copyright the NTPsec project contributors
 * SPDX-License-Identifier: BSD-2-Clause
 *
 */

#include "config.h"

#include <string.h>
#include <ctype.h>

#include "ntp_types.h"
#include "ntp_stdlib.h"

#include "pymodule-mac.h"
#include "hack-ancient-openssl.h"

// Don't include Python.h

#define OPENSSL_SUPPRESS_DEPRECATED 1
#include <openssl/evp.h>
#include <openssl/cmac.h>
#include <openssl/opensslv.h>

// Needed on OpenSSL < 1.1.0
static void init_ssl(void) {
#if OPENSSL_VERSION_NUMBER < 0x10100000L
	static bool init_done = false;
	if (init_done) {
		return;
        }
	init_done = true;
	OpenSSL_add_all_ciphers();
	OpenSSL_add_all_digests();
#endif
}

/* xx = ntp.ntpc.checkname(name)
 * returns false if algorithm name is invalid.
 */
int do_checkname(const char *name)
{
	char upcase[100];
	const EVP_MD *digest;
	const EVP_CIPHER *cipher;

	init_ssl();

        strlcpy(upcase, name, sizeof(upcase));
	for (int i=0; upcase[i]!=0; i++) {
		upcase[i] = toupper((unsigned char)upcase[i]);
	}

        digest = EVP_get_digestbyname(upcase);
	if (NULL != digest) {
		return true;
        }

        if ((strcmp(upcase, "AES") == 0) || (strcmp(upcase, "AES128CMAC") == 0)) {
                strlcpy(upcase, "AES-128", sizeof(upcase));
        }
        strlcat(upcase, "-CBC", sizeof(upcase));
	cipher = EVP_get_cipherbyname(upcase);
	if (NULL != cipher) {
		int length = EVP_CIPHER_key_length(cipher);
		return length;
	}

	return false;
}


// mac = ntp.ntpc.mac(data, key, name)

#if EVP_MAX_MD_SIZE > MAX_MAC_LENGTH
#error "MAX_MAC_LENGTH isn't big enough"
// FIXME: Does this cover CMAC ??
#endif

void do_mac(char *name,
	uint8_t *data, size_t datalen,
	uint8_t *key, size_t keylen,
	uint8_t mac[MAX_MAC_LENGTH], size_t *maclen)
{
	char upcase[100];
	static EVP_MD_CTX *digest_ctx = NULL;
	static CMAC_CTX *cmac_ctx = NULL;
	const EVP_MD *digest;
	const EVP_CIPHER *cipher;
	size_t cipherlen;
	uint8_t newkey[EVP_MAX_KEY_LENGTH];

	init_ssl();

        strlcpy(upcase, name, sizeof(upcase));
	for (int i=0; upcase[i]!=0; i++) {
		upcase[i] = toupper((unsigned char)upcase[i]);
	}

        digest = EVP_get_digestbyname(upcase);
	if (NULL != digest) {
		// Old digest case, MD5, SHA1
		unsigned int maclenint;
		if (NULL == digest_ctx) {
			digest_ctx = EVP_MD_CTX_new();
                }
		if (!EVP_DigestInit_ex(digest_ctx, digest, NULL)) {
			*maclen = 0;
			return;
		}
		EVP_DigestUpdate(digest_ctx, key, keylen);
		EVP_DigestUpdate(digest_ctx, data, (unsigned int)datalen);
		EVP_DigestFinal_ex(digest_ctx, mac, &maclenint);
		if (MAX_MAC_LENGTH < maclenint) {
			maclenint = MAX_MAC_LENGTH;
                }
		*maclen = maclenint;
		return;
	}

        if ((strcmp(upcase, "AES") == 0) || (strcmp(upcase, "AES128CMAC") == 0)) {
                strlcpy(upcase, "AES-128", sizeof(upcase));
        }
        strlcat(upcase, "-CBC", sizeof(upcase));

	cipher = EVP_get_cipherbyname(upcase);
	if (NULL == cipher) {
		*maclen = 0;
		return;
	}
	cipherlen = EVP_CIPHER_key_length(cipher);
	if (cipherlen < keylen) {
		keylen = cipherlen;		// truncate
	} else if (cipherlen > keylen) {
		memcpy(newkey, key, keylen);
		while (cipherlen > keylen) {
			key[keylen++] = 0;	// pad with 0s
                }
		key = newkey;
	}
        /* Coverity CID 462307, 2023 June 11
         * CMAC API is undocumented and deprecated in OpenSSL 3.
         * See libntp/macencrypt.c
         */
	if (NULL == cmac_ctx) {
		cmac_ctx = CMAC_CTX_new();
        }
        if (!CMAC_Init(cmac_ctx, key, keylen, cipher, NULL)) {
                // Shouldn't happen.  Does if wrong key_size.
		*maclen = 0;
		return;
        }
        if (!CMAC_Update(cmac_ctx, data, (unsigned int)datalen)) {
                *maclen = 0;
                return;
        }
        if (!CMAC_Final(cmac_ctx, mac, maclen)) {
                *maclen = 0;
                return;
        }
        if (MAX_MAC_LENGTH < *maclen) {
                *maclen = MAX_MAC_LENGTH;
        }
	return;
}