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