1 /* $OpenBSD: radius_userpass.c,v 1.1 2015/07/20 23:52:29 yasuoka Exp $ */ 2 3 /*- 4 * Copyright (c) 2013 Internet Initiative Japan Inc. 5 * All rights reserved. 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 29 #include <sys/types.h> 30 #include <sys/socket.h> 31 #include <netinet/in.h> 32 33 #include <stdbool.h> 34 #include <stdio.h> 35 #include <stdlib.h> 36 #include <string.h> 37 38 #include <openssl/md5.h> 39 40 #include "radius.h" 41 42 #include "radius_local.h" 43 44 int 45 radius_encrypt_user_password_attr(void *cipher, size_t * clen, 46 const char *plain, const void *ra, const char *secret) 47 { 48 size_t plen = strlen(plain); 49 size_t slen = strlen(secret); 50 char b[16], p[16], *c; 51 size_t off; 52 MD5_CTX ctx; 53 unsigned int i; 54 55 if (*clen < ROUNDUP(plen, 16)) 56 return (-1); 57 58 for (off = 0; off < plen; off += sizeof(p)) { 59 c = ((char *)cipher) + off; 60 memset(p, 0, sizeof(p)); 61 strncpy(p, plain + off, sizeof(p)); /* not strlcpy() */ 62 MD5_Init(&ctx); 63 MD5_Update(&ctx, secret, slen); 64 if (off == 0) 65 MD5_Update(&ctx, ra, 16); 66 else 67 MD5_Update(&ctx, c - 16, 16); 68 MD5_Final(b, &ctx); 69 for (i = 0; i < 16; i++) 70 c[i] = p[i] ^ b[i]; 71 } 72 73 *clen = off; 74 return (0); 75 } 76 77 int 78 radius_decrypt_user_password_attr(char *plain, size_t plen, const void *cipher, 79 size_t clen, const void *ra, const char *secret) 80 { 81 size_t slen = strlen(secret); 82 char b[16]; 83 size_t off; 84 char *p, *c; 85 MD5_CTX ctx; 86 unsigned int i; 87 88 if (clen % 16 != 0) 89 return (-1); 90 if (plen < clen + 1) 91 return (-1); 92 93 for (off = 0; off < clen; off += 16) { 94 c = ((char *)cipher) + off; 95 p = plain + off; 96 MD5_Init(&ctx); 97 MD5_Update(&ctx, secret, slen); 98 if (off == 0) 99 MD5_Update(&ctx, ra, 16); 100 else 101 MD5_Update(&ctx, c - 16, 16); 102 MD5_Final(b, &ctx); 103 for (i = 0; i < 16; i++) 104 p[i] = c[i] ^ b[i]; 105 } 106 107 p = memchr(plain, '\0', off); 108 if (p == NULL) 109 plain[off] = '\0'; 110 else { 111 /* memcspn() does not exist... */ 112 for (p++; p < plain + off; p++) { 113 if (*p != '\0') 114 return (-1); 115 } 116 } 117 118 return (0); 119 } 120 121 int 122 radius_get_user_password_attr(const RADIUS_PACKET * packet, char *buf, 123 size_t len, const char *secret) 124 { 125 char cipher[256]; 126 size_t clen = sizeof(cipher); 127 128 if (radius_get_raw_attr(packet, RADIUS_TYPE_USER_PASSWORD, cipher, 129 &clen) != 0) 130 return (-1); 131 if (radius_decrypt_user_password_attr(buf, len, cipher, clen, 132 radius_get_authenticator_retval(packet), secret) != 0) 133 return (-1); 134 135 return (0); 136 } 137 138 int 139 radius_put_user_password_attr(RADIUS_PACKET * packet, const char *buf, 140 const char *secret) 141 { 142 char cipher[256]; 143 size_t clen = sizeof(cipher); 144 145 if (radius_encrypt_user_password_attr(cipher, &clen, buf, 146 radius_get_authenticator_retval(packet), secret) != 0) 147 return (-1); 148 if (radius_put_raw_attr(packet, RADIUS_TYPE_USER_PASSWORD, cipher, 149 clen) != 0) 150 return (-1); 151 152 return (0); 153 } 154