1216299Ssyrinx/*- 2216299Ssyrinx * Copyright (c) 2010 The FreeBSD Foundation 3216299Ssyrinx * All rights reserved. 4216299Ssyrinx * 5216299Ssyrinx * This software was developed by Shteryana Sotirova Shopova under 6216299Ssyrinx * sponsorship from the FreeBSD Foundation. 7216299Ssyrinx * 8216299Ssyrinx * Redistribution and use in source and binary forms, with or without 9216299Ssyrinx * modification, are permitted provided that the following conditions 10216299Ssyrinx * are met: 11216299Ssyrinx * 1. Redistributions of source code must retain the above copyright 12216299Ssyrinx * notice, this list of conditions and the following disclaimer. 13216299Ssyrinx * 2. Redistributions in binary form must reproduce the above copyright 14216299Ssyrinx * notice, this list of conditions and the following disclaimer in the 15216299Ssyrinx * documentation and/or other materials provided with the distribution. 16216299Ssyrinx * 17216299Ssyrinx * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 18216299Ssyrinx * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19216299Ssyrinx * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20216299Ssyrinx * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 21216299Ssyrinx * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 22216299Ssyrinx * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 23216299Ssyrinx * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 24216299Ssyrinx * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 25216299Ssyrinx * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 26216299Ssyrinx * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 27216299Ssyrinx * SUCH DAMAGE. 28216299Ssyrinx * 29216299Ssyrinx * $FreeBSD$ 30216299Ssyrinx */ 31216299Ssyrinx#include <sys/types.h> 32216299Ssyrinx#include <sys/socket.h> 33216299Ssyrinx#include <stdio.h> 34216299Ssyrinx#include <stdlib.h> 35216299Ssyrinx#include <stddef.h> 36216299Ssyrinx#include <stdarg.h> 37216299Ssyrinx#ifdef HAVE_STDINT_H 38216299Ssyrinx#include <stdint.h> 39216299Ssyrinx#elif defined(HAVE_INTTYPES_H) 40216299Ssyrinx#include <inttypes.h> 41216299Ssyrinx#endif 42216299Ssyrinx#include <string.h> 43216299Ssyrinx#include <ctype.h> 44216299Ssyrinx#include <errno.h> 45216299Ssyrinx#include <netinet/in.h> 46216299Ssyrinx 47216299Ssyrinx#ifdef HAVE_LIBCRYPTO 48216299Ssyrinx#include <openssl/evp.h> 49216299Ssyrinx#endif 50216299Ssyrinx 51216299Ssyrinx#include "asn1.h" 52216299Ssyrinx#include "snmp.h" 53216299Ssyrinx#include "snmppriv.h" 54216299Ssyrinx 55216299Ssyrinx#define SNMP_PRIV_AES_IV_SIZ 16 56216299Ssyrinx#define SNMP_EXTENDED_KEY_SIZ 64 57216299Ssyrinx#define SNMP_AUTH_KEY_LOOPCNT 1048576 58216299Ssyrinx#define SNMP_AUTH_BUF_SIZE 72 59216299Ssyrinx 60216299Ssyrinxstatic const uint8_t ipad = 0x36; 61216299Ssyrinxstatic const uint8_t opad = 0x5c; 62216299Ssyrinx 63216299Ssyrinx#ifdef HAVE_LIBCRYPTO 64216299Ssyrinx 65216299Ssyrinxstatic int32_t 66216299Ssyrinxsnmp_digest_init(const struct snmp_user *user, EVP_MD_CTX *ctx, 67216299Ssyrinx const EVP_MD **dtype, uint32_t *keylen) 68216299Ssyrinx{ 69216299Ssyrinx if (user->auth_proto == SNMP_AUTH_HMAC_MD5) { 70216299Ssyrinx *dtype = EVP_md5(); 71216299Ssyrinx *keylen = SNMP_AUTH_HMACMD5_KEY_SIZ; 72216299Ssyrinx } else if (user->auth_proto == SNMP_AUTH_HMAC_SHA) { 73216299Ssyrinx *dtype = EVP_sha1(); 74216299Ssyrinx *keylen = SNMP_AUTH_HMACSHA_KEY_SIZ; 75216299Ssyrinx } else if (user->auth_proto == SNMP_AUTH_NOAUTH) 76216299Ssyrinx return (0); 77216299Ssyrinx else { 78216299Ssyrinx snmp_error("unknown authentication option - %d", 79216299Ssyrinx user->auth_proto); 80216299Ssyrinx return (-1); 81216299Ssyrinx } 82216299Ssyrinx 83216299Ssyrinx if (EVP_DigestInit(ctx, *dtype) != 1) 84216299Ssyrinx return (-1); 85216299Ssyrinx 86216299Ssyrinx return (1); 87216299Ssyrinx} 88216299Ssyrinx 89216299Ssyrinxenum snmp_code 90216482Ssyrinxsnmp_pdu_calc_digest(const struct snmp_pdu *pdu, uint8_t *digest) 91216299Ssyrinx{ 92216299Ssyrinx uint8_t md[EVP_MAX_MD_SIZE], extkey[SNMP_EXTENDED_KEY_SIZ]; 93216299Ssyrinx uint8_t key1[SNMP_EXTENDED_KEY_SIZ], key2[SNMP_EXTENDED_KEY_SIZ]; 94216299Ssyrinx uint32_t i, keylen, olen; 95216299Ssyrinx int32_t err; 96216299Ssyrinx const EVP_MD *dtype; 97216299Ssyrinx EVP_MD_CTX ctx; 98216299Ssyrinx 99216299Ssyrinx err = snmp_digest_init(&pdu->user, &ctx, &dtype, &keylen); 100216299Ssyrinx if (err < 0) 101216299Ssyrinx return (SNMP_CODE_BADDIGEST); 102216299Ssyrinx else if (err == 0) 103216299Ssyrinx return (SNMP_CODE_OK); 104216299Ssyrinx 105216299Ssyrinx memset(pdu->digest_ptr, 0, sizeof(pdu->msg_digest)); 106216299Ssyrinx memcpy(extkey, pdu->user.auth_key, keylen); 107216299Ssyrinx memset(extkey + keylen, 0, sizeof(extkey) - keylen); 108216299Ssyrinx 109216299Ssyrinx for (i = 0; i < SNMP_EXTENDED_KEY_SIZ; i++) { 110216299Ssyrinx key1[i] = extkey[i] ^ ipad; 111216299Ssyrinx key2[i] = extkey[i] ^ opad; 112216299Ssyrinx } 113216299Ssyrinx 114216299Ssyrinx if (EVP_DigestUpdate(&ctx, key1, SNMP_EXTENDED_KEY_SIZ) != 1 || 115216299Ssyrinx EVP_DigestUpdate(&ctx, pdu->outer_ptr, pdu->outer_len) != 1 || 116216299Ssyrinx EVP_DigestFinal(&ctx, md, &olen) != 1) 117216299Ssyrinx goto failed; 118216299Ssyrinx 119216299Ssyrinx if (EVP_DigestInit(&ctx, dtype) != 1 || 120216299Ssyrinx EVP_DigestUpdate(&ctx, key2, SNMP_EXTENDED_KEY_SIZ) != 1 || 121216299Ssyrinx EVP_DigestUpdate(&ctx, md, olen) != 1 || 122216299Ssyrinx EVP_DigestFinal(&ctx, md, &olen) != 1) 123216299Ssyrinx goto failed; 124216299Ssyrinx 125216299Ssyrinx if (olen < SNMP_USM_AUTH_SIZE) { 126216299Ssyrinx snmp_error("bad digest size - %d", olen); 127216299Ssyrinx EVP_MD_CTX_cleanup(&ctx); 128216299Ssyrinx return (SNMP_CODE_BADDIGEST); 129216299Ssyrinx } 130216299Ssyrinx 131216299Ssyrinx memcpy(digest, md, SNMP_USM_AUTH_SIZE); 132216299Ssyrinx EVP_MD_CTX_cleanup(&ctx); 133216299Ssyrinx return (SNMP_CODE_OK); 134216299Ssyrinx 135216299Ssyrinxfailed: 136216299Ssyrinx EVP_MD_CTX_cleanup(&ctx); 137216299Ssyrinx return (SNMP_CODE_BADDIGEST); 138216299Ssyrinx} 139216299Ssyrinx 140216299Ssyrinxstatic int32_t 141216299Ssyrinxsnmp_pdu_cipher_init(const struct snmp_pdu *pdu, int32_t len, 142216482Ssyrinx const EVP_CIPHER **ctype, uint8_t *piv) 143216299Ssyrinx{ 144216299Ssyrinx int i; 145216299Ssyrinx uint32_t netint; 146216299Ssyrinx 147216299Ssyrinx if (pdu->user.priv_proto == SNMP_PRIV_DES) { 148216299Ssyrinx if (len % 8 != 0) 149216299Ssyrinx return (-1); 150216299Ssyrinx *ctype = EVP_des_cbc(); 151216299Ssyrinx memcpy(piv, pdu->msg_salt, sizeof(pdu->msg_salt)); 152216299Ssyrinx for (i = 0; i < 8; i++) 153216299Ssyrinx piv[i] = piv[i] ^ pdu->user.priv_key[8 + i]; 154216299Ssyrinx } else if (pdu->user.priv_proto == SNMP_PRIV_AES) { 155216299Ssyrinx *ctype = EVP_aes_128_cfb128(); 156216299Ssyrinx netint = htonl(pdu->engine.engine_boots); 157216299Ssyrinx memcpy(piv, &netint, sizeof(netint)); 158216299Ssyrinx piv += sizeof(netint); 159216299Ssyrinx netint = htonl(pdu->engine.engine_time); 160216299Ssyrinx memcpy(piv, &netint, sizeof(netint)); 161216299Ssyrinx piv += sizeof(netint); 162216299Ssyrinx memcpy(piv, pdu->msg_salt, sizeof(pdu->msg_salt)); 163216299Ssyrinx } else if (pdu->user.priv_proto == SNMP_PRIV_NOPRIV) 164216299Ssyrinx return (0); 165216299Ssyrinx else { 166216299Ssyrinx snmp_error("unknown privacy option - %d", pdu->user.priv_proto); 167216299Ssyrinx return (-1); 168216299Ssyrinx } 169216299Ssyrinx 170216299Ssyrinx return (1); 171216299Ssyrinx} 172216299Ssyrinx 173216299Ssyrinxenum snmp_code 174216482Ssyrinxsnmp_pdu_encrypt(const struct snmp_pdu *pdu) 175216299Ssyrinx{ 176216299Ssyrinx int32_t err, olen; 177216299Ssyrinx uint8_t iv[SNMP_PRIV_AES_IV_SIZ]; 178216299Ssyrinx const EVP_CIPHER *ctype; 179216299Ssyrinx EVP_CIPHER_CTX ctx; 180216299Ssyrinx 181216482Ssyrinx err = snmp_pdu_cipher_init(pdu, pdu->scoped_len, &ctype, iv); 182216299Ssyrinx if (err < 0) 183216299Ssyrinx return (SNMP_CODE_EDECRYPT); 184216299Ssyrinx else if (err == 0) 185216299Ssyrinx return (SNMP_CODE_OK); 186216299Ssyrinx 187216299Ssyrinx if (EVP_EncryptInit(&ctx, ctype, pdu->user.priv_key, iv) != 1) 188216299Ssyrinx return (SNMP_CODE_FAILED); 189216299Ssyrinx 190216299Ssyrinx if (EVP_EncryptUpdate(&ctx, pdu->scoped_ptr, &olen, pdu->scoped_ptr, 191216299Ssyrinx pdu->scoped_len) != 1 || 192216299Ssyrinx EVP_EncryptFinal(&ctx, pdu->scoped_ptr + olen, &olen) != 1) { 193216299Ssyrinx EVP_CIPHER_CTX_cleanup(&ctx); 194216299Ssyrinx return (SNMP_CODE_FAILED); 195216299Ssyrinx } 196216299Ssyrinx 197216299Ssyrinx EVP_CIPHER_CTX_cleanup(&ctx); 198216299Ssyrinx return (SNMP_CODE_OK); 199216299Ssyrinx} 200216299Ssyrinx 201216299Ssyrinxenum snmp_code 202216482Ssyrinxsnmp_pdu_decrypt(const struct snmp_pdu *pdu) 203216299Ssyrinx{ 204216299Ssyrinx int32_t err, olen; 205216299Ssyrinx uint8_t iv[SNMP_PRIV_AES_IV_SIZ]; 206216299Ssyrinx const EVP_CIPHER *ctype; 207216299Ssyrinx EVP_CIPHER_CTX ctx; 208216299Ssyrinx 209216482Ssyrinx err = snmp_pdu_cipher_init(pdu, pdu->scoped_len, &ctype, iv); 210216299Ssyrinx if (err < 0) 211216299Ssyrinx return (SNMP_CODE_EDECRYPT); 212216299Ssyrinx else if (err == 0) 213216299Ssyrinx return (SNMP_CODE_OK); 214216299Ssyrinx 215216299Ssyrinx if (EVP_DecryptInit(&ctx, ctype, pdu->user.priv_key, iv) != 1 || 216216299Ssyrinx EVP_CIPHER_CTX_set_padding(&ctx, 0) != 1) 217216299Ssyrinx return (SNMP_CODE_EDECRYPT); 218216299Ssyrinx 219216299Ssyrinx if (EVP_DecryptUpdate(&ctx, pdu->scoped_ptr, &olen, pdu->scoped_ptr, 220216299Ssyrinx pdu->scoped_len) != 1 || 221216299Ssyrinx EVP_DecryptFinal(&ctx, pdu->scoped_ptr + olen, &olen) != 1) { 222216299Ssyrinx EVP_CIPHER_CTX_cleanup(&ctx); 223216299Ssyrinx return (SNMP_CODE_EDECRYPT); 224216299Ssyrinx } 225216299Ssyrinx 226216299Ssyrinx EVP_CIPHER_CTX_cleanup(&ctx); 227216299Ssyrinx return (SNMP_CODE_OK); 228216299Ssyrinx} 229216299Ssyrinx 230216299Ssyrinx/* [RFC 3414] - A.2. Password to Key Algorithm */ 231216299Ssyrinxenum snmp_code 232216299Ssyrinxsnmp_passwd_to_keys(struct snmp_user *user, char *passwd) 233216299Ssyrinx{ 234216299Ssyrinx int err, loop, i, pwdlen; 235216299Ssyrinx uint32_t keylen, olen; 236216299Ssyrinx const EVP_MD *dtype; 237216299Ssyrinx EVP_MD_CTX ctx; 238216299Ssyrinx uint8_t authbuf[SNMP_AUTH_BUF_SIZE]; 239216299Ssyrinx 240216299Ssyrinx if (passwd == NULL || user == NULL) 241216299Ssyrinx return (SNMP_CODE_FAILED); 242216299Ssyrinx 243216299Ssyrinx err = snmp_digest_init(user, &ctx, &dtype, &keylen); 244216299Ssyrinx if (err < 0) 245216299Ssyrinx return (SNMP_CODE_BADDIGEST); 246216299Ssyrinx else if (err == 0) 247216299Ssyrinx return (SNMP_CODE_OK); 248216299Ssyrinx 249216299Ssyrinx memset(user->auth_key, 0, sizeof(user->auth_key)); 250216299Ssyrinx pwdlen = strlen(passwd); 251216299Ssyrinx 252216299Ssyrinx for (loop = 0; loop < SNMP_AUTH_KEY_LOOPCNT; loop += i) { 253216299Ssyrinx for (i = 0; i < SNMP_EXTENDED_KEY_SIZ; i++) 254216299Ssyrinx authbuf[i] = passwd[(loop + i) % pwdlen]; 255216299Ssyrinx if (EVP_DigestUpdate(&ctx, authbuf, SNMP_EXTENDED_KEY_SIZ) != 1) 256216299Ssyrinx goto failed; 257216299Ssyrinx } 258216299Ssyrinx 259216299Ssyrinx if (EVP_DigestFinal(&ctx, user->auth_key, &olen) != 1) 260216299Ssyrinx goto failed; 261216299Ssyrinx 262216299Ssyrinx EVP_MD_CTX_cleanup(&ctx); 263216299Ssyrinx return (SNMP_CODE_OK); 264216299Ssyrinx 265216299Ssyrinxfailed: 266216299Ssyrinx EVP_MD_CTX_cleanup(&ctx); 267216299Ssyrinx return (SNMP_CODE_BADDIGEST); 268216299Ssyrinx} 269216299Ssyrinx 270216299Ssyrinx/* [RFC 3414] - 2.6. Key Localization Algorithm */ 271216299Ssyrinxenum snmp_code 272216299Ssyrinxsnmp_get_local_keys(struct snmp_user *user, uint8_t *eid, uint32_t elen) 273216299Ssyrinx{ 274216299Ssyrinx int err; 275216299Ssyrinx uint32_t keylen, olen; 276216299Ssyrinx const EVP_MD *dtype; 277216299Ssyrinx EVP_MD_CTX ctx; 278216299Ssyrinx uint8_t authbuf[SNMP_AUTH_BUF_SIZE]; 279216299Ssyrinx 280216299Ssyrinx if (user == NULL || eid == NULL || elen > SNMP_ENGINE_ID_SIZ) 281216299Ssyrinx return (SNMP_CODE_FAILED); 282216299Ssyrinx 283216299Ssyrinx memset(user->priv_key, 0, sizeof(user->priv_key)); 284216299Ssyrinx memset(authbuf, 0, sizeof(authbuf)); 285216299Ssyrinx 286216299Ssyrinx err = snmp_digest_init(user, &ctx, &dtype, &keylen); 287216299Ssyrinx if (err < 0) 288216299Ssyrinx return (SNMP_CODE_BADDIGEST); 289216299Ssyrinx else if (err == 0) 290216299Ssyrinx return (SNMP_CODE_OK); 291216299Ssyrinx 292216299Ssyrinx memcpy(authbuf, user->auth_key, keylen); 293216299Ssyrinx memcpy(authbuf + keylen, eid, elen); 294216299Ssyrinx memcpy(authbuf + keylen + elen, user->auth_key, keylen); 295216299Ssyrinx 296216299Ssyrinx if (EVP_DigestUpdate(&ctx, authbuf, 2 * keylen + elen) != 1 || 297216299Ssyrinx EVP_DigestFinal(&ctx, user->auth_key, &olen) != 1) { 298216299Ssyrinx EVP_MD_CTX_cleanup(&ctx); 299216299Ssyrinx return (SNMP_CODE_BADDIGEST); 300216299Ssyrinx } 301216299Ssyrinx EVP_MD_CTX_cleanup(&ctx); 302216299Ssyrinx 303216299Ssyrinx if (user->priv_proto != SNMP_PRIV_NOPRIV) 304216299Ssyrinx memcpy(user->priv_key, user->auth_key, sizeof(user->priv_key)); 305216299Ssyrinx 306216299Ssyrinx return (SNMP_CODE_OK); 307216299Ssyrinx} 308216299Ssyrinx 309216299Ssyrinxenum snmp_code 310216299Ssyrinxsnmp_calc_keychange(struct snmp_user *user, uint8_t *keychange) 311216299Ssyrinx{ 312216482Ssyrinx int32_t err, rvalue[SNMP_AUTH_HMACSHA_KEY_SIZ / 4]; 313216482Ssyrinx uint32_t i, keylen, olen; 314216299Ssyrinx const EVP_MD *dtype; 315216299Ssyrinx EVP_MD_CTX ctx; 316216299Ssyrinx 317216299Ssyrinx err = snmp_digest_init(user, &ctx, &dtype, &keylen); 318216299Ssyrinx if (err < 0) 319216299Ssyrinx return (SNMP_CODE_BADDIGEST); 320216299Ssyrinx else if (err == 0) 321216299Ssyrinx return (SNMP_CODE_OK); 322216299Ssyrinx 323216299Ssyrinx for (i = 0; i < keylen / 4; i++) 324216299Ssyrinx rvalue[i] = random(); 325216299Ssyrinx 326216299Ssyrinx memcpy(keychange, user->auth_key, keylen); 327216299Ssyrinx memcpy(keychange + keylen, rvalue, keylen); 328216299Ssyrinx 329216299Ssyrinx if (EVP_DigestUpdate(&ctx, keychange, 2 * keylen) != 1 || 330216299Ssyrinx EVP_DigestFinal(&ctx, keychange, &olen) != 1) { 331216299Ssyrinx EVP_MD_CTX_cleanup(&ctx); 332216299Ssyrinx return (SNMP_CODE_BADDIGEST); 333216299Ssyrinx } 334216299Ssyrinx 335216299Ssyrinx EVP_MD_CTX_cleanup(&ctx); 336216299Ssyrinx return (SNMP_CODE_OK); 337216299Ssyrinx} 338216299Ssyrinx 339216299Ssyrinx#else /* !HAVE_LIBCRYPTO */ 340216299Ssyrinx 341216299Ssyrinxenum snmp_code 342216482Ssyrinxsnmp_pdu_calc_digest(const struct snmp_pdu *pdu, uint8_t *digest __unused) 343216299Ssyrinx{ 344216299Ssyrinx if (pdu->user.auth_proto != SNMP_AUTH_NOAUTH) 345216299Ssyrinx return (SNMP_CODE_BADSECLEVEL); 346216299Ssyrinx 347216299Ssyrinx 348216299Ssyrinx return (SNMP_CODE_OK); 349216299Ssyrinx} 350216299Ssyrinx 351216299Ssyrinxenum snmp_code 352216482Ssyrinxsnmp_pdu_encrypt(const struct snmp_pdu *pdu) 353216299Ssyrinx{ 354216299Ssyrinx if (pdu->user.priv_proto != SNMP_PRIV_NOPRIV) 355216299Ssyrinx return (SNMP_CODE_BADSECLEVEL); 356216299Ssyrinx 357216299Ssyrinx return (SNMP_CODE_OK); 358216299Ssyrinx} 359216299Ssyrinx 360216299Ssyrinxenum snmp_code 361216482Ssyrinxsnmp_pdu_decrypt(const struct snmp_pdu *pdu) 362216299Ssyrinx{ 363216299Ssyrinx if (pdu->user.priv_proto != SNMP_PRIV_NOPRIV) 364216299Ssyrinx return (SNMP_CODE_BADSECLEVEL); 365216299Ssyrinx 366216299Ssyrinx return (SNMP_CODE_OK); 367216299Ssyrinx} 368216299Ssyrinx 369216299Ssyrinxint 370216299Ssyrinxsnmp_passwd_to_keys(struct snmp_user *user, char *passwd __unused) 371216299Ssyrinx{ 372216299Ssyrinx if (user->auth_proto == SNMP_AUTH_NOAUTH && 373216299Ssyrinx user->priv_proto == SNMP_PRIV_NOPRIV) 374216299Ssyrinx return (SNMP_CODE_OK); 375216299Ssyrinx 376216299Ssyrinx errno = EPROTONOSUPPORT; 377216299Ssyrinx 378216299Ssyrinx return (SNMP_CODE_FAILED); 379216299Ssyrinx} 380216299Ssyrinx 381216299Ssyrinxint 382216299Ssyrinxsnmp_get_local_keys(struct snmp_user *user, uint8_t *eid __unused, 383216299Ssyrinx uint32_t elen __unused) 384216299Ssyrinx{ 385216299Ssyrinx if (user->auth_proto == SNMP_AUTH_NOAUTH && 386216299Ssyrinx user->priv_proto == SNMP_PRIV_NOPRIV) 387216299Ssyrinx return (SNMP_CODE_OK); 388216299Ssyrinx 389216299Ssyrinx errno = EPROTONOSUPPORT; 390216299Ssyrinx 391216299Ssyrinx return (SNMP_CODE_FAILED); 392216299Ssyrinx} 393216299Ssyrinx 394216299Ssyrinxenum snmp_code 395216299Ssyrinxsnmp_calc_keychange(struct snmp_user *user __unused, 396216299Ssyrinx uint8_t *keychange __unused) 397216299Ssyrinx{ 398216299Ssyrinx errno = EPROTONOSUPPORT; 399216299Ssyrinx return (SNMP_CODE_FAILED); 400216299Ssyrinx} 401216299Ssyrinx 402216299Ssyrinx#endif /* HAVE_LIBCRYPTO */ 403