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