xref: /freebsd/contrib/bsnmp/lib/snmpcrypto.c (revision e9a4946830630eefd3e76323903d0f4682deab48)
1*e9a49468SShteryana Shopova /*-
2*e9a49468SShteryana Shopova  * Copyright (c) 2010 The FreeBSD Foundation
3*e9a49468SShteryana Shopova  * All rights reserved.
4*e9a49468SShteryana Shopova  *
5*e9a49468SShteryana Shopova  * This software was developed by Shteryana Sotirova Shopova under
6*e9a49468SShteryana Shopova  * sponsorship from the FreeBSD Foundation.
7*e9a49468SShteryana Shopova  *
8*e9a49468SShteryana Shopova  * Redistribution and use in source and binary forms, with or without
9*e9a49468SShteryana Shopova  * modification, are permitted provided that the following conditions
10*e9a49468SShteryana Shopova  * are met:
11*e9a49468SShteryana Shopova  * 1. Redistributions of source code must retain the above copyright
12*e9a49468SShteryana Shopova  *    notice, this list of conditions and the following disclaimer.
13*e9a49468SShteryana Shopova  * 2. Redistributions in binary form must reproduce the above copyright
14*e9a49468SShteryana Shopova  *    notice, this list of conditions and the following disclaimer in the
15*e9a49468SShteryana Shopova  *    documentation and/or other materials provided with the distribution.
16*e9a49468SShteryana Shopova  *
17*e9a49468SShteryana Shopova  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
18*e9a49468SShteryana Shopova  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19*e9a49468SShteryana Shopova  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20*e9a49468SShteryana Shopova  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
21*e9a49468SShteryana Shopova  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22*e9a49468SShteryana Shopova  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23*e9a49468SShteryana Shopova  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24*e9a49468SShteryana Shopova  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25*e9a49468SShteryana Shopova  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26*e9a49468SShteryana Shopova  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27*e9a49468SShteryana Shopova  * SUCH DAMAGE.
28*e9a49468SShteryana Shopova  *
29*e9a49468SShteryana Shopova  * $FreeBSD$
30*e9a49468SShteryana Shopova  */
31*e9a49468SShteryana Shopova #include <sys/types.h>
32*e9a49468SShteryana Shopova #include <sys/socket.h>
33*e9a49468SShteryana Shopova #include <stdio.h>
34*e9a49468SShteryana Shopova #include <stdlib.h>
35*e9a49468SShteryana Shopova #include <stddef.h>
36*e9a49468SShteryana Shopova #include <stdarg.h>
37*e9a49468SShteryana Shopova #ifdef HAVE_STDINT_H
38*e9a49468SShteryana Shopova #include <stdint.h>
39*e9a49468SShteryana Shopova #elif defined(HAVE_INTTYPES_H)
40*e9a49468SShteryana Shopova #include <inttypes.h>
41*e9a49468SShteryana Shopova #endif
42*e9a49468SShteryana Shopova #include <string.h>
43*e9a49468SShteryana Shopova #include <ctype.h>
44*e9a49468SShteryana Shopova #include <errno.h>
45*e9a49468SShteryana Shopova #include <netinet/in.h>
46*e9a49468SShteryana Shopova 
47*e9a49468SShteryana Shopova #ifdef HAVE_LIBCRYPTO
48*e9a49468SShteryana Shopova #include <openssl/evp.h>
49*e9a49468SShteryana Shopova #endif
50*e9a49468SShteryana Shopova 
51*e9a49468SShteryana Shopova #include "asn1.h"
52*e9a49468SShteryana Shopova #include "snmp.h"
53*e9a49468SShteryana Shopova #include "snmppriv.h"
54*e9a49468SShteryana Shopova 
55*e9a49468SShteryana Shopova #define	SNMP_PRIV_AES_IV_SIZ		16
56*e9a49468SShteryana Shopova #define	SNMP_EXTENDED_KEY_SIZ		64
57*e9a49468SShteryana Shopova #define	SNMP_AUTH_KEY_LOOPCNT		1048576
58*e9a49468SShteryana Shopova #define	SNMP_AUTH_BUF_SIZE		72
59*e9a49468SShteryana Shopova 
60*e9a49468SShteryana Shopova static const uint8_t ipad = 0x36;
61*e9a49468SShteryana Shopova static const uint8_t opad = 0x5c;
62*e9a49468SShteryana Shopova 
63*e9a49468SShteryana Shopova #ifdef HAVE_LIBCRYPTO
64*e9a49468SShteryana Shopova 
65*e9a49468SShteryana Shopova static int32_t
66*e9a49468SShteryana Shopova snmp_digest_init(const struct snmp_user *user, EVP_MD_CTX *ctx,
67*e9a49468SShteryana Shopova     const EVP_MD **dtype, uint32_t *keylen)
68*e9a49468SShteryana Shopova {
69*e9a49468SShteryana Shopova 	if (user->auth_proto == SNMP_AUTH_HMAC_MD5) {
70*e9a49468SShteryana Shopova 		*dtype = EVP_md5();
71*e9a49468SShteryana Shopova 		*keylen = SNMP_AUTH_HMACMD5_KEY_SIZ;
72*e9a49468SShteryana Shopova 	} else if (user->auth_proto == SNMP_AUTH_HMAC_SHA) {
73*e9a49468SShteryana Shopova 		*dtype = EVP_sha1();
74*e9a49468SShteryana Shopova 		*keylen = SNMP_AUTH_HMACSHA_KEY_SIZ;
75*e9a49468SShteryana Shopova 	} else if (user->auth_proto == SNMP_AUTH_NOAUTH)
76*e9a49468SShteryana Shopova 		return (0);
77*e9a49468SShteryana Shopova 	else {
78*e9a49468SShteryana Shopova 		snmp_error("unknown authentication option - %d",
79*e9a49468SShteryana Shopova 		    user->auth_proto);
80*e9a49468SShteryana Shopova 		return (-1);
81*e9a49468SShteryana Shopova 	}
82*e9a49468SShteryana Shopova 
83*e9a49468SShteryana Shopova 	if (EVP_DigestInit(ctx, *dtype) != 1)
84*e9a49468SShteryana Shopova 		return (-1);
85*e9a49468SShteryana Shopova 
86*e9a49468SShteryana Shopova 	return (1);
87*e9a49468SShteryana Shopova }
88*e9a49468SShteryana Shopova 
89*e9a49468SShteryana Shopova enum snmp_code
90*e9a49468SShteryana Shopova snmp_pdu_calc_digest(struct asn_buf *b, const struct snmp_pdu *pdu,
91*e9a49468SShteryana Shopova     uint8_t *digest)
92*e9a49468SShteryana Shopova {
93*e9a49468SShteryana Shopova 	uint8_t md[EVP_MAX_MD_SIZE], extkey[SNMP_EXTENDED_KEY_SIZ];
94*e9a49468SShteryana Shopova 	uint8_t key1[SNMP_EXTENDED_KEY_SIZ], key2[SNMP_EXTENDED_KEY_SIZ];
95*e9a49468SShteryana Shopova 	uint32_t i, keylen, olen;
96*e9a49468SShteryana Shopova 	int32_t err;
97*e9a49468SShteryana Shopova 	const EVP_MD *dtype;
98*e9a49468SShteryana Shopova 	EVP_MD_CTX ctx;
99*e9a49468SShteryana Shopova 
100*e9a49468SShteryana Shopova 	err = snmp_digest_init(&pdu->user, &ctx, &dtype, &keylen);
101*e9a49468SShteryana Shopova 	if (err < 0)
102*e9a49468SShteryana Shopova 		return (SNMP_CODE_BADDIGEST);
103*e9a49468SShteryana Shopova 	else if (err == 0)
104*e9a49468SShteryana Shopova 		return (SNMP_CODE_OK);
105*e9a49468SShteryana Shopova 
106*e9a49468SShteryana Shopova 	memset(pdu->digest_ptr, 0, sizeof(pdu->msg_digest));
107*e9a49468SShteryana Shopova 	memcpy(extkey, pdu->user.auth_key, keylen);
108*e9a49468SShteryana Shopova 	memset(extkey + keylen, 0, sizeof(extkey) - keylen);
109*e9a49468SShteryana Shopova 
110*e9a49468SShteryana Shopova 	for (i = 0; i < SNMP_EXTENDED_KEY_SIZ; i++) {
111*e9a49468SShteryana Shopova 		key1[i] = extkey[i] ^ ipad;
112*e9a49468SShteryana Shopova 		key2[i] = extkey[i] ^ opad;
113*e9a49468SShteryana Shopova 	}
114*e9a49468SShteryana Shopova 
115*e9a49468SShteryana Shopova 	if (EVP_DigestUpdate(&ctx, key1, SNMP_EXTENDED_KEY_SIZ) != 1 ||
116*e9a49468SShteryana Shopova 	    EVP_DigestUpdate(&ctx, pdu->outer_ptr, pdu->outer_len) != 1 ||
117*e9a49468SShteryana Shopova 	    EVP_DigestFinal(&ctx, md, &olen) != 1)
118*e9a49468SShteryana Shopova 		goto failed;
119*e9a49468SShteryana Shopova 
120*e9a49468SShteryana Shopova 	if (EVP_DigestInit(&ctx, dtype) != 1 ||
121*e9a49468SShteryana Shopova 	    EVP_DigestUpdate(&ctx, key2, SNMP_EXTENDED_KEY_SIZ) != 1 ||
122*e9a49468SShteryana Shopova 	    EVP_DigestUpdate(&ctx, md, olen) != 1 ||
123*e9a49468SShteryana Shopova 	    EVP_DigestFinal(&ctx, md, &olen) != 1)
124*e9a49468SShteryana Shopova 		goto failed;
125*e9a49468SShteryana Shopova 
126*e9a49468SShteryana Shopova 	if (olen < SNMP_USM_AUTH_SIZE) {
127*e9a49468SShteryana Shopova 		snmp_error("bad digest size - %d", olen);
128*e9a49468SShteryana Shopova 		EVP_MD_CTX_cleanup(&ctx);
129*e9a49468SShteryana Shopova 		return (SNMP_CODE_BADDIGEST);
130*e9a49468SShteryana Shopova 	}
131*e9a49468SShteryana Shopova 
132*e9a49468SShteryana Shopova 	memcpy(digest, md, SNMP_USM_AUTH_SIZE);
133*e9a49468SShteryana Shopova 	EVP_MD_CTX_cleanup(&ctx);
134*e9a49468SShteryana Shopova 	return (SNMP_CODE_OK);
135*e9a49468SShteryana Shopova 
136*e9a49468SShteryana Shopova failed:
137*e9a49468SShteryana Shopova 	EVP_MD_CTX_cleanup(&ctx);
138*e9a49468SShteryana Shopova 	return (SNMP_CODE_BADDIGEST);
139*e9a49468SShteryana Shopova }
140*e9a49468SShteryana Shopova 
141*e9a49468SShteryana Shopova static int32_t
142*e9a49468SShteryana Shopova snmp_pdu_cipher_init(const struct snmp_pdu *pdu, int32_t len,
143*e9a49468SShteryana Shopova     EVP_CIPHER_CTX *ctx, const EVP_CIPHER **ctype, uint8_t *piv)
144*e9a49468SShteryana Shopova {
145*e9a49468SShteryana Shopova 	int i;
146*e9a49468SShteryana Shopova 	uint32_t netint;
147*e9a49468SShteryana Shopova 
148*e9a49468SShteryana Shopova 	if (pdu->user.priv_proto == SNMP_PRIV_DES) {
149*e9a49468SShteryana Shopova 		if (len  % 8 != 0)
150*e9a49468SShteryana Shopova 			return (-1);
151*e9a49468SShteryana Shopova 		*ctype = EVP_des_cbc();
152*e9a49468SShteryana Shopova 		memcpy(piv, pdu->msg_salt, sizeof(pdu->msg_salt));
153*e9a49468SShteryana Shopova 		for (i = 0; i < 8; i++)
154*e9a49468SShteryana Shopova 			piv[i] = piv[i] ^ pdu->user.priv_key[8 + i];
155*e9a49468SShteryana Shopova 	} else if (pdu->user.priv_proto == SNMP_PRIV_AES) {
156*e9a49468SShteryana Shopova 		*ctype = EVP_aes_128_cfb128();
157*e9a49468SShteryana Shopova 		netint = htonl(pdu->engine.engine_boots);
158*e9a49468SShteryana Shopova 		memcpy(piv, &netint, sizeof(netint));
159*e9a49468SShteryana Shopova 		piv += sizeof(netint);
160*e9a49468SShteryana Shopova 		netint = htonl(pdu->engine.engine_time);
161*e9a49468SShteryana Shopova 		memcpy(piv, &netint, sizeof(netint));
162*e9a49468SShteryana Shopova 		piv += sizeof(netint);
163*e9a49468SShteryana Shopova 		memcpy(piv, pdu->msg_salt, sizeof(pdu->msg_salt));
164*e9a49468SShteryana Shopova 	} else if (pdu->user.priv_proto == SNMP_PRIV_NOPRIV)
165*e9a49468SShteryana Shopova 		return (0);
166*e9a49468SShteryana Shopova 	else {
167*e9a49468SShteryana Shopova 		snmp_error("unknown privacy option - %d", pdu->user.priv_proto);
168*e9a49468SShteryana Shopova 		return (-1);
169*e9a49468SShteryana Shopova 	}
170*e9a49468SShteryana Shopova 
171*e9a49468SShteryana Shopova 	return (1);
172*e9a49468SShteryana Shopova }
173*e9a49468SShteryana Shopova 
174*e9a49468SShteryana Shopova enum snmp_code
175*e9a49468SShteryana Shopova snmp_pdu_encrypt(struct asn_buf *b, const struct snmp_pdu *pdu)
176*e9a49468SShteryana Shopova {
177*e9a49468SShteryana Shopova 	int32_t err, olen;
178*e9a49468SShteryana Shopova 	uint8_t iv[SNMP_PRIV_AES_IV_SIZ];
179*e9a49468SShteryana Shopova 	const EVP_CIPHER *ctype;
180*e9a49468SShteryana Shopova 	EVP_CIPHER_CTX ctx;
181*e9a49468SShteryana Shopova 
182*e9a49468SShteryana Shopova 	err = snmp_pdu_cipher_init(pdu, pdu->scoped_len, &ctx, &ctype, iv);
183*e9a49468SShteryana Shopova 	if (err < 0)
184*e9a49468SShteryana Shopova 		return (SNMP_CODE_EDECRYPT);
185*e9a49468SShteryana Shopova 	else if (err == 0)
186*e9a49468SShteryana Shopova 		return (SNMP_CODE_OK);
187*e9a49468SShteryana Shopova 
188*e9a49468SShteryana Shopova 	if (EVP_EncryptInit(&ctx, ctype, pdu->user.priv_key, iv) != 1)
189*e9a49468SShteryana Shopova 		return (SNMP_CODE_FAILED);
190*e9a49468SShteryana Shopova 
191*e9a49468SShteryana Shopova 	if (EVP_EncryptUpdate(&ctx, pdu->scoped_ptr, &olen, pdu->scoped_ptr,
192*e9a49468SShteryana Shopova 	    pdu->scoped_len) != 1 ||
193*e9a49468SShteryana Shopova 	    EVP_EncryptFinal(&ctx, pdu->scoped_ptr + olen, &olen) != 1) {
194*e9a49468SShteryana Shopova 		EVP_CIPHER_CTX_cleanup(&ctx);
195*e9a49468SShteryana Shopova 		return (SNMP_CODE_FAILED);
196*e9a49468SShteryana Shopova 	}
197*e9a49468SShteryana Shopova 
198*e9a49468SShteryana Shopova 	EVP_CIPHER_CTX_cleanup(&ctx);
199*e9a49468SShteryana Shopova 	return (SNMP_CODE_OK);
200*e9a49468SShteryana Shopova }
201*e9a49468SShteryana Shopova 
202*e9a49468SShteryana Shopova enum snmp_code
203*e9a49468SShteryana Shopova snmp_pdu_decrypt(struct asn_buf *b, const struct snmp_pdu *pdu)
204*e9a49468SShteryana Shopova {
205*e9a49468SShteryana Shopova 	int32_t err, olen;
206*e9a49468SShteryana Shopova 	uint8_t iv[SNMP_PRIV_AES_IV_SIZ];
207*e9a49468SShteryana Shopova 	const EVP_CIPHER *ctype;
208*e9a49468SShteryana Shopova 	EVP_CIPHER_CTX ctx;
209*e9a49468SShteryana Shopova 
210*e9a49468SShteryana Shopova 	err = snmp_pdu_cipher_init(pdu, pdu->scoped_len, &ctx, &ctype, iv);
211*e9a49468SShteryana Shopova 	if (err < 0)
212*e9a49468SShteryana Shopova 		return (SNMP_CODE_EDECRYPT);
213*e9a49468SShteryana Shopova 	else if (err == 0)
214*e9a49468SShteryana Shopova 		return (SNMP_CODE_OK);
215*e9a49468SShteryana Shopova 
216*e9a49468SShteryana Shopova 	if (EVP_DecryptInit(&ctx, ctype, pdu->user.priv_key, iv) != 1 ||
217*e9a49468SShteryana Shopova 	    EVP_CIPHER_CTX_set_padding(&ctx, 0) != 1)
218*e9a49468SShteryana Shopova 		return (SNMP_CODE_EDECRYPT);
219*e9a49468SShteryana Shopova 
220*e9a49468SShteryana Shopova 	if (EVP_DecryptUpdate(&ctx, pdu->scoped_ptr, &olen, pdu->scoped_ptr,
221*e9a49468SShteryana Shopova 	    pdu->scoped_len) != 1 ||
222*e9a49468SShteryana Shopova 	    EVP_DecryptFinal(&ctx, pdu->scoped_ptr + olen, &olen) != 1) {
223*e9a49468SShteryana Shopova 		EVP_CIPHER_CTX_cleanup(&ctx);
224*e9a49468SShteryana Shopova 		return (SNMP_CODE_EDECRYPT);
225*e9a49468SShteryana Shopova 	}
226*e9a49468SShteryana Shopova 
227*e9a49468SShteryana Shopova 	EVP_CIPHER_CTX_cleanup(&ctx);
228*e9a49468SShteryana Shopova 	return (SNMP_CODE_OK);
229*e9a49468SShteryana Shopova }
230*e9a49468SShteryana Shopova 
231*e9a49468SShteryana Shopova /* [RFC 3414] - A.2. Password to Key Algorithm */
232*e9a49468SShteryana Shopova enum snmp_code
233*e9a49468SShteryana Shopova snmp_passwd_to_keys(struct snmp_user *user, char *passwd)
234*e9a49468SShteryana Shopova {
235*e9a49468SShteryana Shopova 	int err, loop, i, pwdlen;
236*e9a49468SShteryana Shopova 	uint32_t  keylen, olen;
237*e9a49468SShteryana Shopova 	const EVP_MD *dtype;
238*e9a49468SShteryana Shopova 	EVP_MD_CTX ctx;
239*e9a49468SShteryana Shopova 	uint8_t authbuf[SNMP_AUTH_BUF_SIZE];
240*e9a49468SShteryana Shopova 
241*e9a49468SShteryana Shopova 	if (passwd == NULL || user == NULL)
242*e9a49468SShteryana Shopova 		return (SNMP_CODE_FAILED);
243*e9a49468SShteryana Shopova 
244*e9a49468SShteryana Shopova 	err = snmp_digest_init(user, &ctx, &dtype, &keylen);
245*e9a49468SShteryana Shopova 	if (err < 0)
246*e9a49468SShteryana Shopova 		return (SNMP_CODE_BADDIGEST);
247*e9a49468SShteryana Shopova 	else if (err == 0)
248*e9a49468SShteryana Shopova 		return (SNMP_CODE_OK);
249*e9a49468SShteryana Shopova 
250*e9a49468SShteryana Shopova 	memset(user->auth_key, 0, sizeof(user->auth_key));
251*e9a49468SShteryana Shopova 	pwdlen = strlen(passwd);
252*e9a49468SShteryana Shopova 
253*e9a49468SShteryana Shopova 	for (loop = 0; loop < SNMP_AUTH_KEY_LOOPCNT; loop += i) {
254*e9a49468SShteryana Shopova 		for (i = 0; i < SNMP_EXTENDED_KEY_SIZ; i++)
255*e9a49468SShteryana Shopova 			authbuf[i] = passwd[(loop + i) % pwdlen];
256*e9a49468SShteryana Shopova 		if (EVP_DigestUpdate(&ctx, authbuf, SNMP_EXTENDED_KEY_SIZ) != 1)
257*e9a49468SShteryana Shopova 			goto failed;
258*e9a49468SShteryana Shopova 	}
259*e9a49468SShteryana Shopova 
260*e9a49468SShteryana Shopova 	if (EVP_DigestFinal(&ctx, user->auth_key, &olen) != 1)
261*e9a49468SShteryana Shopova 		goto failed;
262*e9a49468SShteryana Shopova 
263*e9a49468SShteryana Shopova 	EVP_MD_CTX_cleanup(&ctx);
264*e9a49468SShteryana Shopova 	return (SNMP_CODE_OK);
265*e9a49468SShteryana Shopova 
266*e9a49468SShteryana Shopova failed:
267*e9a49468SShteryana Shopova 	EVP_MD_CTX_cleanup(&ctx);
268*e9a49468SShteryana Shopova 	return (SNMP_CODE_BADDIGEST);
269*e9a49468SShteryana Shopova }
270*e9a49468SShteryana Shopova 
271*e9a49468SShteryana Shopova /* [RFC 3414] - 2.6. Key Localization Algorithm */
272*e9a49468SShteryana Shopova enum snmp_code
273*e9a49468SShteryana Shopova snmp_get_local_keys(struct snmp_user *user, uint8_t *eid, uint32_t elen)
274*e9a49468SShteryana Shopova {
275*e9a49468SShteryana Shopova 	int err;
276*e9a49468SShteryana Shopova 	uint32_t  keylen, olen;
277*e9a49468SShteryana Shopova 	const EVP_MD *dtype;
278*e9a49468SShteryana Shopova 	EVP_MD_CTX ctx;
279*e9a49468SShteryana Shopova 	uint8_t authbuf[SNMP_AUTH_BUF_SIZE];
280*e9a49468SShteryana Shopova 
281*e9a49468SShteryana Shopova 	if (user == NULL || eid == NULL || elen > SNMP_ENGINE_ID_SIZ)
282*e9a49468SShteryana Shopova 		return (SNMP_CODE_FAILED);
283*e9a49468SShteryana Shopova 
284*e9a49468SShteryana Shopova 	memset(user->priv_key, 0, sizeof(user->priv_key));
285*e9a49468SShteryana Shopova 	memset(authbuf, 0, sizeof(authbuf));
286*e9a49468SShteryana Shopova 
287*e9a49468SShteryana Shopova 	err = snmp_digest_init(user, &ctx, &dtype, &keylen);
288*e9a49468SShteryana Shopova 	if (err < 0)
289*e9a49468SShteryana Shopova 		return (SNMP_CODE_BADDIGEST);
290*e9a49468SShteryana Shopova 	else if (err == 0)
291*e9a49468SShteryana Shopova 		return (SNMP_CODE_OK);
292*e9a49468SShteryana Shopova 
293*e9a49468SShteryana Shopova 	memcpy(authbuf, user->auth_key, keylen);
294*e9a49468SShteryana Shopova 	memcpy(authbuf + keylen, eid, elen);
295*e9a49468SShteryana Shopova 	memcpy(authbuf + keylen + elen, user->auth_key, keylen);
296*e9a49468SShteryana Shopova 
297*e9a49468SShteryana Shopova 	if (EVP_DigestUpdate(&ctx, authbuf, 2 * keylen + elen) != 1 ||
298*e9a49468SShteryana Shopova 	    EVP_DigestFinal(&ctx, user->auth_key, &olen) != 1) {
299*e9a49468SShteryana Shopova 		EVP_MD_CTX_cleanup(&ctx);
300*e9a49468SShteryana Shopova 		return (SNMP_CODE_BADDIGEST);
301*e9a49468SShteryana Shopova 	}
302*e9a49468SShteryana Shopova 	EVP_MD_CTX_cleanup(&ctx);
303*e9a49468SShteryana Shopova 
304*e9a49468SShteryana Shopova 	if (user->priv_proto != SNMP_PRIV_NOPRIV)
305*e9a49468SShteryana Shopova 		memcpy(user->priv_key, user->auth_key, sizeof(user->priv_key));
306*e9a49468SShteryana Shopova 
307*e9a49468SShteryana Shopova 	return (SNMP_CODE_OK);
308*e9a49468SShteryana Shopova }
309*e9a49468SShteryana Shopova 
310*e9a49468SShteryana Shopova enum snmp_code
311*e9a49468SShteryana Shopova snmp_calc_keychange(struct snmp_user *user, uint8_t *keychange)
312*e9a49468SShteryana Shopova {
313*e9a49468SShteryana Shopova 	int32_t i, err, rvalue[SNMP_AUTH_HMACSHA_KEY_SIZ / 4];
314*e9a49468SShteryana Shopova 	uint32_t  keylen, olen;
315*e9a49468SShteryana Shopova 	const EVP_MD *dtype;
316*e9a49468SShteryana Shopova 	EVP_MD_CTX ctx;
317*e9a49468SShteryana Shopova 
318*e9a49468SShteryana Shopova 	err = snmp_digest_init(user, &ctx, &dtype, &keylen);
319*e9a49468SShteryana Shopova 	if (err < 0)
320*e9a49468SShteryana Shopova 		return (SNMP_CODE_BADDIGEST);
321*e9a49468SShteryana Shopova 	else if (err == 0)
322*e9a49468SShteryana Shopova 		return (SNMP_CODE_OK);
323*e9a49468SShteryana Shopova 
324*e9a49468SShteryana Shopova 	for (i = 0; i < keylen / 4; i++)
325*e9a49468SShteryana Shopova 		rvalue[i] = random();
326*e9a49468SShteryana Shopova 
327*e9a49468SShteryana Shopova 	memcpy(keychange, user->auth_key, keylen);
328*e9a49468SShteryana Shopova 	memcpy(keychange + keylen, rvalue, keylen);
329*e9a49468SShteryana Shopova 
330*e9a49468SShteryana Shopova 	if (EVP_DigestUpdate(&ctx, keychange, 2 * keylen) != 1 ||
331*e9a49468SShteryana Shopova 	    EVP_DigestFinal(&ctx, keychange, &olen) != 1) {
332*e9a49468SShteryana Shopova 		EVP_MD_CTX_cleanup(&ctx);
333*e9a49468SShteryana Shopova 		return (SNMP_CODE_BADDIGEST);
334*e9a49468SShteryana Shopova 	}
335*e9a49468SShteryana Shopova 
336*e9a49468SShteryana Shopova 	EVP_MD_CTX_cleanup(&ctx);
337*e9a49468SShteryana Shopova 	return (SNMP_CODE_OK);
338*e9a49468SShteryana Shopova }
339*e9a49468SShteryana Shopova 
340*e9a49468SShteryana Shopova #else /* !HAVE_LIBCRYPTO */
341*e9a49468SShteryana Shopova 
342*e9a49468SShteryana Shopova enum snmp_code
343*e9a49468SShteryana Shopova snmp_pdu_calc_digest(struct asn_buf *b __unused, const struct snmp_pdu *pdu,
344*e9a49468SShteryana Shopova     uint8_t *digest __unused)
345*e9a49468SShteryana Shopova {
346*e9a49468SShteryana Shopova 	if  (pdu->user.auth_proto != SNMP_AUTH_NOAUTH)
347*e9a49468SShteryana Shopova 		return (SNMP_CODE_BADSECLEVEL);
348*e9a49468SShteryana Shopova 
349*e9a49468SShteryana Shopova 
350*e9a49468SShteryana Shopova 	return (SNMP_CODE_OK);
351*e9a49468SShteryana Shopova }
352*e9a49468SShteryana Shopova 
353*e9a49468SShteryana Shopova enum snmp_code
354*e9a49468SShteryana Shopova snmp_pdu_encrypt(struct asn_buf *b __unused, const struct snmp_pdu *pdu)
355*e9a49468SShteryana Shopova {
356*e9a49468SShteryana Shopova 	if (pdu->user.priv_proto != SNMP_PRIV_NOPRIV)
357*e9a49468SShteryana Shopova 		return (SNMP_CODE_BADSECLEVEL);
358*e9a49468SShteryana Shopova 
359*e9a49468SShteryana Shopova 	return (SNMP_CODE_OK);
360*e9a49468SShteryana Shopova }
361*e9a49468SShteryana Shopova 
362*e9a49468SShteryana Shopova enum snmp_code
363*e9a49468SShteryana Shopova snmp_pdu_decrypt(struct asn_buf *b __unused, const struct snmp_pdu *pdu)
364*e9a49468SShteryana Shopova {
365*e9a49468SShteryana Shopova 	if (pdu->user.priv_proto != SNMP_PRIV_NOPRIV)
366*e9a49468SShteryana Shopova 		return (SNMP_CODE_BADSECLEVEL);
367*e9a49468SShteryana Shopova 
368*e9a49468SShteryana Shopova 	return (SNMP_CODE_OK);
369*e9a49468SShteryana Shopova }
370*e9a49468SShteryana Shopova 
371*e9a49468SShteryana Shopova int
372*e9a49468SShteryana Shopova snmp_passwd_to_keys(struct snmp_user *user, char *passwd __unused)
373*e9a49468SShteryana Shopova {
374*e9a49468SShteryana Shopova 	if (user->auth_proto == SNMP_AUTH_NOAUTH &&
375*e9a49468SShteryana Shopova 	    user->priv_proto == SNMP_PRIV_NOPRIV)
376*e9a49468SShteryana Shopova 		return (SNMP_CODE_OK);
377*e9a49468SShteryana Shopova 
378*e9a49468SShteryana Shopova 	errno = EPROTONOSUPPORT;
379*e9a49468SShteryana Shopova 
380*e9a49468SShteryana Shopova 	return (SNMP_CODE_FAILED);
381*e9a49468SShteryana Shopova }
382*e9a49468SShteryana Shopova 
383*e9a49468SShteryana Shopova int
384*e9a49468SShteryana Shopova snmp_get_local_keys(struct snmp_user *user, uint8_t *eid __unused,
385*e9a49468SShteryana Shopova     uint32_t elen __unused)
386*e9a49468SShteryana Shopova {
387*e9a49468SShteryana Shopova 	if (user->auth_proto == SNMP_AUTH_NOAUTH &&
388*e9a49468SShteryana Shopova 	    user->priv_proto == SNMP_PRIV_NOPRIV)
389*e9a49468SShteryana Shopova 		return (SNMP_CODE_OK);
390*e9a49468SShteryana Shopova 
391*e9a49468SShteryana Shopova 	errno = EPROTONOSUPPORT;
392*e9a49468SShteryana Shopova 
393*e9a49468SShteryana Shopova 	return (SNMP_CODE_FAILED);
394*e9a49468SShteryana Shopova }
395*e9a49468SShteryana Shopova 
396*e9a49468SShteryana Shopova enum snmp_code
397*e9a49468SShteryana Shopova snmp_calc_keychange(struct snmp_user *user __unused,
398*e9a49468SShteryana Shopova     uint8_t *keychange __unused)
399*e9a49468SShteryana Shopova {
400*e9a49468SShteryana Shopova 	errno = EPROTONOSUPPORT;
401*e9a49468SShteryana Shopova 	return (SNMP_CODE_FAILED);
402*e9a49468SShteryana Shopova }
403*e9a49468SShteryana Shopova 
404*e9a49468SShteryana Shopova #endif /* HAVE_LIBCRYPTO */
405