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 err = snmp_digest_init(&pdu->user, &ctx, &dtype, &keylen); 100 if (err < 0) 101 return (SNMP_CODE_BADDIGEST); 102 else if (err == 0) 103 return (SNMP_CODE_OK); 104 105 memset(pdu->digest_ptr, 0, sizeof(pdu->msg_digest)); 106 memcpy(extkey, pdu->user.auth_key, keylen); 107 memset(extkey + keylen, 0, sizeof(extkey) - keylen); 108 109 for (i = 0; i < SNMP_EXTENDED_KEY_SIZ; i++) { 110 key1[i] = extkey[i] ^ ipad; 111 key2[i] = extkey[i] ^ opad; 112 } 113 114 if (EVP_DigestUpdate(&ctx, key1, SNMP_EXTENDED_KEY_SIZ) != 1 || 115 EVP_DigestUpdate(&ctx, pdu->outer_ptr, pdu->outer_len) != 1 || 116 EVP_DigestFinal(&ctx, md, &olen) != 1) 117 goto failed; 118 119 if (EVP_DigestInit(&ctx, dtype) != 1 || 120 EVP_DigestUpdate(&ctx, key2, SNMP_EXTENDED_KEY_SIZ) != 1 || 121 EVP_DigestUpdate(&ctx, md, olen) != 1 || 122 EVP_DigestFinal(&ctx, md, &olen) != 1) 123 goto failed; 124 125 if (olen < SNMP_USM_AUTH_SIZE) { 126 snmp_error("bad digest size - %d", olen); 127 EVP_MD_CTX_cleanup(&ctx); 128 return (SNMP_CODE_BADDIGEST); 129 } 130 131 memcpy(digest, md, SNMP_USM_AUTH_SIZE); 132 EVP_MD_CTX_cleanup(&ctx); 133 return (SNMP_CODE_OK); 134 135 failed: 136 EVP_MD_CTX_cleanup(&ctx); 137 return (SNMP_CODE_BADDIGEST); 138 } 139 140 static int32_t 141 snmp_pdu_cipher_init(const struct snmp_pdu *pdu, int32_t len, 142 const EVP_CIPHER **ctype, uint8_t *piv) 143 { 144 int i; 145 uint32_t netint; 146 147 if (pdu->user.priv_proto == SNMP_PRIV_DES) { 148 if (len % 8 != 0) 149 return (-1); 150 *ctype = EVP_des_cbc(); 151 memcpy(piv, pdu->msg_salt, sizeof(pdu->msg_salt)); 152 for (i = 0; i < 8; i++) 153 piv[i] = piv[i] ^ pdu->user.priv_key[8 + i]; 154 } else if (pdu->user.priv_proto == SNMP_PRIV_AES) { 155 *ctype = EVP_aes_128_cfb128(); 156 netint = htonl(pdu->engine.engine_boots); 157 memcpy(piv, &netint, sizeof(netint)); 158 piv += sizeof(netint); 159 netint = htonl(pdu->engine.engine_time); 160 memcpy(piv, &netint, sizeof(netint)); 161 piv += sizeof(netint); 162 memcpy(piv, pdu->msg_salt, sizeof(pdu->msg_salt)); 163 } else if (pdu->user.priv_proto == SNMP_PRIV_NOPRIV) 164 return (0); 165 else { 166 snmp_error("unknown privacy option - %d", pdu->user.priv_proto); 167 return (-1); 168 } 169 170 return (1); 171 } 172 173 enum snmp_code 174 snmp_pdu_encrypt(const struct snmp_pdu *pdu) 175 { 176 int32_t err, olen; 177 uint8_t iv[SNMP_PRIV_AES_IV_SIZ]; 178 const EVP_CIPHER *ctype; 179 EVP_CIPHER_CTX ctx; 180 181 err = snmp_pdu_cipher_init(pdu, pdu->scoped_len, &ctype, iv); 182 if (err < 0) 183 return (SNMP_CODE_EDECRYPT); 184 else if (err == 0) 185 return (SNMP_CODE_OK); 186 187 if (EVP_EncryptInit(&ctx, ctype, pdu->user.priv_key, iv) != 1) 188 return (SNMP_CODE_FAILED); 189 190 if (EVP_EncryptUpdate(&ctx, pdu->scoped_ptr, &olen, pdu->scoped_ptr, 191 pdu->scoped_len) != 1 || 192 EVP_EncryptFinal(&ctx, pdu->scoped_ptr + olen, &olen) != 1) { 193 EVP_CIPHER_CTX_cleanup(&ctx); 194 return (SNMP_CODE_FAILED); 195 } 196 197 EVP_CIPHER_CTX_cleanup(&ctx); 198 return (SNMP_CODE_OK); 199 } 200 201 enum snmp_code 202 snmp_pdu_decrypt(const struct snmp_pdu *pdu) 203 { 204 int32_t err, olen; 205 uint8_t iv[SNMP_PRIV_AES_IV_SIZ]; 206 const EVP_CIPHER *ctype; 207 EVP_CIPHER_CTX ctx; 208 209 err = snmp_pdu_cipher_init(pdu, pdu->scoped_len, &ctype, iv); 210 if (err < 0) 211 return (SNMP_CODE_EDECRYPT); 212 else if (err == 0) 213 return (SNMP_CODE_OK); 214 215 if (EVP_DecryptInit(&ctx, ctype, pdu->user.priv_key, iv) != 1 || 216 EVP_CIPHER_CTX_set_padding(&ctx, 0) != 1) 217 return (SNMP_CODE_EDECRYPT); 218 219 if (EVP_DecryptUpdate(&ctx, pdu->scoped_ptr, &olen, pdu->scoped_ptr, 220 pdu->scoped_len) != 1 || 221 EVP_DecryptFinal(&ctx, pdu->scoped_ptr + olen, &olen) != 1) { 222 EVP_CIPHER_CTX_cleanup(&ctx); 223 return (SNMP_CODE_EDECRYPT); 224 } 225 226 EVP_CIPHER_CTX_cleanup(&ctx); 227 return (SNMP_CODE_OK); 228 } 229 230 /* [RFC 3414] - A.2. Password to Key Algorithm */ 231 enum snmp_code 232 snmp_passwd_to_keys(struct snmp_user *user, char *passwd) 233 { 234 int err, loop, i, pwdlen; 235 uint32_t keylen, olen; 236 const EVP_MD *dtype; 237 EVP_MD_CTX ctx; 238 uint8_t authbuf[SNMP_AUTH_BUF_SIZE]; 239 240 if (passwd == NULL || user == NULL) 241 return (SNMP_CODE_FAILED); 242 243 err = snmp_digest_init(user, &ctx, &dtype, &keylen); 244 if (err < 0) 245 return (SNMP_CODE_BADDIGEST); 246 else if (err == 0) 247 return (SNMP_CODE_OK); 248 249 memset(user->auth_key, 0, sizeof(user->auth_key)); 250 pwdlen = strlen(passwd); 251 252 for (loop = 0; loop < SNMP_AUTH_KEY_LOOPCNT; loop += i) { 253 for (i = 0; i < SNMP_EXTENDED_KEY_SIZ; i++) 254 authbuf[i] = passwd[(loop + i) % pwdlen]; 255 if (EVP_DigestUpdate(&ctx, authbuf, SNMP_EXTENDED_KEY_SIZ) != 1) 256 goto failed; 257 } 258 259 if (EVP_DigestFinal(&ctx, user->auth_key, &olen) != 1) 260 goto failed; 261 262 EVP_MD_CTX_cleanup(&ctx); 263 return (SNMP_CODE_OK); 264 265 failed: 266 EVP_MD_CTX_cleanup(&ctx); 267 return (SNMP_CODE_BADDIGEST); 268 } 269 270 /* [RFC 3414] - 2.6. Key Localization Algorithm */ 271 enum snmp_code 272 snmp_get_local_keys(struct snmp_user *user, uint8_t *eid, uint32_t elen) 273 { 274 int err; 275 uint32_t keylen, olen; 276 const EVP_MD *dtype; 277 EVP_MD_CTX ctx; 278 uint8_t authbuf[SNMP_AUTH_BUF_SIZE]; 279 280 if (user == NULL || eid == NULL || elen > SNMP_ENGINE_ID_SIZ) 281 return (SNMP_CODE_FAILED); 282 283 memset(user->priv_key, 0, sizeof(user->priv_key)); 284 memset(authbuf, 0, sizeof(authbuf)); 285 286 err = snmp_digest_init(user, &ctx, &dtype, &keylen); 287 if (err < 0) 288 return (SNMP_CODE_BADDIGEST); 289 else if (err == 0) 290 return (SNMP_CODE_OK); 291 292 memcpy(authbuf, user->auth_key, keylen); 293 memcpy(authbuf + keylen, eid, elen); 294 memcpy(authbuf + keylen + elen, user->auth_key, keylen); 295 296 if (EVP_DigestUpdate(&ctx, authbuf, 2 * keylen + elen) != 1 || 297 EVP_DigestFinal(&ctx, user->auth_key, &olen) != 1) { 298 EVP_MD_CTX_cleanup(&ctx); 299 return (SNMP_CODE_BADDIGEST); 300 } 301 EVP_MD_CTX_cleanup(&ctx); 302 303 if (user->priv_proto != SNMP_PRIV_NOPRIV) 304 memcpy(user->priv_key, user->auth_key, sizeof(user->priv_key)); 305 306 return (SNMP_CODE_OK); 307 } 308 309 enum snmp_code 310 snmp_calc_keychange(struct snmp_user *user, uint8_t *keychange) 311 { 312 int32_t err, rvalue[SNMP_AUTH_HMACSHA_KEY_SIZ / 4]; 313 uint32_t i, keylen, olen; 314 const EVP_MD *dtype; 315 EVP_MD_CTX ctx; 316 317 err = snmp_digest_init(user, &ctx, &dtype, &keylen); 318 if (err < 0) 319 return (SNMP_CODE_BADDIGEST); 320 else if (err == 0) 321 return (SNMP_CODE_OK); 322 323 for (i = 0; i < keylen / 4; i++) 324 rvalue[i] = random(); 325 326 memcpy(keychange, user->auth_key, keylen); 327 memcpy(keychange + keylen, rvalue, keylen); 328 329 if (EVP_DigestUpdate(&ctx, keychange, 2 * keylen) != 1 || 330 EVP_DigestFinal(&ctx, keychange, &olen) != 1) { 331 EVP_MD_CTX_cleanup(&ctx); 332 return (SNMP_CODE_BADDIGEST); 333 } 334 335 EVP_MD_CTX_cleanup(&ctx); 336 return (SNMP_CODE_OK); 337 } 338 339 #else /* !HAVE_LIBCRYPTO */ 340 341 enum snmp_code 342 snmp_pdu_calc_digest(const struct snmp_pdu *pdu, uint8_t *digest __unused) 343 { 344 if (pdu->user.auth_proto != SNMP_AUTH_NOAUTH) 345 return (SNMP_CODE_BADSECLEVEL); 346 347 348 return (SNMP_CODE_OK); 349 } 350 351 enum snmp_code 352 snmp_pdu_encrypt(const struct snmp_pdu *pdu) 353 { 354 if (pdu->user.priv_proto != SNMP_PRIV_NOPRIV) 355 return (SNMP_CODE_BADSECLEVEL); 356 357 return (SNMP_CODE_OK); 358 } 359 360 enum snmp_code 361 snmp_pdu_decrypt(const struct snmp_pdu *pdu) 362 { 363 if (pdu->user.priv_proto != SNMP_PRIV_NOPRIV) 364 return (SNMP_CODE_BADSECLEVEL); 365 366 return (SNMP_CODE_OK); 367 } 368 369 enum snmp_code 370 snmp_passwd_to_keys(struct snmp_user *user, char *passwd __unused) 371 { 372 if (user->auth_proto == SNMP_AUTH_NOAUTH && 373 user->priv_proto == SNMP_PRIV_NOPRIV) 374 return (SNMP_CODE_OK); 375 376 errno = EPROTONOSUPPORT; 377 378 return (SNMP_CODE_FAILED); 379 } 380 381 enum snmp_code 382 snmp_get_local_keys(struct snmp_user *user, uint8_t *eid __unused, 383 uint32_t elen __unused) 384 { 385 if (user->auth_proto == SNMP_AUTH_NOAUTH && 386 user->priv_proto == SNMP_PRIV_NOPRIV) 387 return (SNMP_CODE_OK); 388 389 errno = EPROTONOSUPPORT; 390 391 return (SNMP_CODE_FAILED); 392 } 393 394 enum snmp_code 395 snmp_calc_keychange(struct snmp_user *user __unused, 396 uint8_t *keychange __unused) 397 { 398 errno = EPROTONOSUPPORT; 399 return (SNMP_CODE_FAILED); 400 } 401 402 #endif /* HAVE_LIBCRYPTO */ 403