Changeset 689 in openpam
- Timestamp:
- Jul 12, 2013, 10:47:14 AM (8 years ago)
- Location:
- trunk
- Files:
-
- 3 edited
- 2 copied
Legend:
- Unmodified
- Added
- Removed
-
trunk/include/security/oath_types.h
r678 r689 43 43 unsigned int timestep; /* in seconds */ 44 44 45 /* housekeeping */ 46 unsigned int mapped:1; 47 unsigned int locked:1; 48 45 49 /* hash algorithm */ 46 50 enum oath_hash hash; -
trunk/lib/liboath/Makefile.am
r654 r689 10 10 oath_hotp.c \ 11 11 oath_totp.c \ 12 oath_key_alloc.c \ 13 oath_key_free.c \ 12 14 oath_key.c 13 15 -
trunk/lib/liboath/oath_key.c
r679 r689 39 39 #include <inttypes.h> 40 40 #include <limits.h> 41 #include <stdint.h>42 41 #include <stdio.h> 43 42 #include <stdlib.h> … … 51 50 52 51 #include <security/oath.h> 53 54 /*55 * Allocate a struct oath_key with sufficient additional space for the56 * label and key.57 */58 struct oath_key *59 oath_key_alloc(void)60 {61 struct oath_key *key;62 63 if ((key = calloc(1, sizeof *key)) == NULL) {64 openpam_log(PAM_LOG_ERROR, "malloc(): %s", strerror(errno));65 return (NULL);66 }67 /* XXX should try to wire */68 return (key);69 }70 71 /*72 * Wipe and free a struct oath_key73 */74 void75 oath_key_free(struct oath_key *key)76 {77 78 if (key != NULL) {79 memset(key, 0, sizeof *key);80 free(key);81 }82 }83 52 84 53 /* -
trunk/lib/liboath/oath_key_alloc.c
r680 r689 34 34 #endif 35 35 36 #include <sys/ types.h>36 #include <sys/mman.h> 37 37 38 #include <errno.h>39 #include <inttypes.h>40 #include <limits.h>41 38 #include <stdint.h> 42 #include <stdio.h>43 39 #include <stdlib.h> 44 40 #include <string.h> … … 46 42 #include <security/pam_appl.h> 47 43 #include <security/openpam.h> 48 49 #include "openpam_asprintf.h"50 #include "openpam_strlcmp.h"51 52 44 #include <security/oath.h> 53 45 54 46 /* 55 * Allocate a struct oath_key with sufficient additional space for the 56 * label and key. 47 * OATH 48 * 49 * Allocates an OATH key structure 57 50 */ 51 58 52 struct oath_key * 59 53 oath_key_alloc(void) … … 61 55 struct oath_key *key; 62 56 63 if ((key = calloc(1, sizeof *key)) == NULL) { 64 openpam_log(PAM_LOG_ERROR, "malloc(): %s", strerror(errno)); 65 return (NULL); 57 if ((key = mmap(NULL, sizeof *key, PROT_READ|PROT_WRITE, 58 MAP_ANON|MAP_NOCORE, -1, 0)) == NULL) { 59 memset(key, 0, sizeof *key); 60 key->mapped = 1; 61 if (mlock(key, sizeof *key) == 0) 62 key->locked = 1; 63 } else { 64 openpam_log(PAM_LOG_ERROR, "mmap(): %m"); 65 if ((key = calloc(sizeof *key, 1)) == NULL) 66 openpam_log(PAM_LOG_ERROR, "malloc(): %m"); 66 67 } 67 /* XXX should try to wire */68 68 return (key); 69 69 } 70 70 71 /* 72 * Wipe and free a struct oath_key 71 /** 72 * The =oath_key_alloc function allocates and initializes an OATH key 73 * structure. 74 * 75 * Keys allocated with =oath_key_alloc must be freed using =oath_key_free. 76 * 77 * >oath_key_free 78 * 79 * AUTHOR UIO 73 80 */ 74 void75 oath_key_free(struct oath_key *key)76 {77 78 if (key != NULL) {79 memset(key, 0, sizeof *key);80 free(key);81 }82 }83 84 /*85 * Allocate a struct oath_key and populate it from a Google Authenticator86 * otpauth URI87 */88 struct oath_key *89 oath_key_from_uri(const char *uri)90 {91 struct oath_key *key;92 const char *p, *q, *r;93 uintmax_t n;94 char *e;95 96 if ((key = oath_key_alloc()) == NULL)97 return (NULL);98 99 /* check method */100 p = uri;101 if (strlcmp("otpauth://", p, 10) != 0)102 goto invalid;103 p += 10;104 105 /* check mode (hotp = event, totp = time-sync) */106 if ((q = strchr(p, '/')) == NULL)107 goto invalid;108 if (strlcmp("hotp", p, q - p) == 0) {109 key->mode = om_hotp;110 } else if (strlcmp("totp", p, q - p) == 0) {111 key->mode = om_totp;112 } else {113 goto invalid;114 }115 p = q + 1;116 117 /* extract label */118 if ((q = strchr(p, '?')) == NULL)119 goto invalid;120 if ((key->labellen = q - p + 1) > sizeof key->label)121 goto invalid;122 memcpy(key->label, p, q - p);123 key->label[q - p] = '\0';124 p = q + 1;125 126 /* extract parameters */127 key->counter = UINT64_MAX;128 while (*p != '\0') {129 if ((q = strchr(p, '=')) == NULL)130 goto invalid;131 q = q + 1;132 if ((r = strchr(p, '&')) == NULL)133 r = strchr(p, '\0');134 if (r < q)135 /* & before = */136 goto invalid;137 /* p points to key, q points to value, r points to & or NUL */138 if (strlcmp("secret=", p, q - p) == 0) {139 if (key->keylen != 0)140 /* dupe */141 goto invalid;142 key->keylen = sizeof key->key;143 if (base32_dec(q, r - q, key->key, &key->keylen) != 0)144 goto invalid;145 if (base32_enclen(key->keylen) != (size_t)(r - q))146 goto invalid;147 } else if (strlcmp("algorithm=", p, q - p) == 0) {148 if (key->hash != oh_undef)149 /* dupe */150 goto invalid;151 if (strlcmp("SHA1", q, r - q) == 0)152 key->hash = oh_sha1;153 else if (strlcmp("SHA256", q, r - q) == 0)154 key->hash = oh_sha256;155 else if (strlcmp("SHA512", q, r - q) == 0)156 key->hash = oh_sha512;157 else if (strlcmp("MD5", q, r - q) == 0)158 key->hash = oh_md5;159 else160 goto invalid;161 } else if (strlcmp("digits=", p, q - p) == 0) {162 if (key->digits != 0)163 /* dupe */164 goto invalid;165 /* only 6 or 8 */166 if (r - q != 1 || (*q != '6' && *q != '8'))167 goto invalid;168 key->digits = *q - '0';169 } else if (strlcmp("counter=", p, q - p) == 0) {170 if (key->counter != UINT64_MAX)171 /* dupe */172 goto invalid;173 n = strtoumax(q, &e, 10);174 if (e != r || n >= UINT64_MAX)175 goto invalid;176 key->counter = (uint64_t)n;177 } else if (strlcmp("period=", p, q - p) == 0) {178 if (key->timestep != 0)179 /* dupe */180 goto invalid;181 n = strtoumax(q, &e, 10);182 if (e != r || n > OATH_MAX_TIMESTEP)183 goto invalid;184 key->timestep = n;185 } else {186 goto invalid;187 }188 /* final parameter? */189 if (*r == '\0')190 break;191 /* skip & and continue */192 p = r + 1;193 }194 195 /* sanity checks and default values */196 if (key->mode == om_hotp) {197 if (key->timestep != 0)198 goto invalid;199 if (key->counter == UINTMAX_MAX)200 key->counter = 0;201 } else if (key->mode == om_totp) {202 if (key->counter != UINTMAX_MAX)203 goto invalid;204 if (key->timestep == 0)205 key->timestep = OATH_DEF_TIMESTEP;206 } else {207 /* unreachable */208 oath_key_free(key);209 return (NULL);210 }211 if (key->hash == oh_undef)212 key->hash = oh_sha1;213 if (key->digits == 0)214 key->digits = 6;215 if (key->keylen == 0)216 goto invalid;217 return (key);218 219 invalid:220 openpam_log(PAM_LOG_NOTICE, "invalid OATH URI: %s", uri);221 oath_key_free(key);222 return (NULL);223 }224 225 struct oath_key *226 oath_key_from_file(const char *filename)227 {228 struct oath_key *key;229 FILE *f;230 char *line;231 size_t len;232 233 if ((f = fopen(filename, "r")) == NULL)234 return (NULL);235 /* get first non-empty non-comment line */236 line = openpam_readline(f, NULL, &len);237 if (strlcmp("otpauth://", line, len) == 0) {238 key = oath_key_from_uri(line);239 } else {240 openpam_log(PAM_LOG_ERROR,241 "unrecognized key file format: %s", filename);242 key = NULL;243 }244 fclose(f);245 return (key);246 }247 248 char *249 oath_key_to_uri(const struct oath_key *key)250 {251 const char *hash;252 char *tmp, *uri;253 size_t kslen, urilen;254 255 switch (key->hash) {256 case oh_sha1:257 hash = "SHA1";258 break;259 case oh_sha256:260 hash = "SHA256";261 break;262 case oh_sha512:263 hash = "SHA512";264 break;265 case oh_md5:266 hash = "MD5";267 break;268 default:269 return (NULL);270 }271 272 if (key->mode == om_hotp) {273 urilen = asprintf(&uri, "otpauth://"274 "%s/%s?algorithm=%s&digits=%d&counter=%ju&secret=",275 "hotp", key->label, hash, key->digits,276 (uintmax_t)key->counter);277 } else if (key->mode == om_totp) {278 urilen = asprintf(&uri, "otpauth://"279 "%s/%s?algorithm=%s&digits=%d&period=%u&secret=",280 "totp", key->label, hash, key->digits, key->timestep);281 } else {282 /* unreachable */283 return (NULL);284 }285 286 /* compute length of base32-encoded key and append it */287 kslen = base32_enclen(key->keylen) + 1;288 if ((tmp = realloc(uri, urilen + kslen)) == NULL) {289 free(uri);290 return (NULL);291 }292 uri = tmp;293 if (base32_enc(key->key, key->keylen, uri + urilen, &kslen) != 0) {294 free(uri);295 return (NULL);296 }297 298 return (uri);299 }300 301 struct oath_key *302 oath_dummy_key(enum oath_mode mode, enum oath_hash hash, unsigned int digits)303 {304 struct oath_key *key;305 306 if ((key = oath_key_alloc()) == NULL)307 return (NULL);308 key->mode = mode;309 key->digits = digits;310 key->counter = 0;311 key->timestep = 30;312 key->hash = hash;313 strcpy(key->label, "oath-dummy-key");314 key->labellen = strlen(key->label);315 key->keylen = sizeof key->key;316 return (key);317 } -
trunk/lib/liboath/oath_key_free.c
r680 r689 34 34 #endif 35 35 36 #include <sys/ types.h>36 #include <sys/mman.h> 37 37 38 #include <errno.h>39 #include <inttypes.h>40 #include <limits.h>41 38 #include <stdint.h> 42 #include <stdio.h>43 39 #include <stdlib.h> 44 40 #include <string.h> … … 46 42 #include <security/pam_appl.h> 47 43 #include <security/openpam.h> 48 49 #include "openpam_asprintf.h"50 #include "openpam_strlcmp.h"51 52 44 #include <security/oath.h> 53 45 54 46 /* 55 * Allocate a struct oath_key with sufficient additional space for the 56 * label and key. 47 * OATH 48 * 49 * Wipes and frees an OATH key structure 57 50 */ 58 struct oath_key *59 oath_key_alloc(void)60 {61 struct oath_key *key;62 51 63 if ((key = calloc(1, sizeof *key)) == NULL) {64 openpam_log(PAM_LOG_ERROR, "malloc(): %s", strerror(errno));65 return (NULL);66 }67 /* XXX should try to wire */68 return (key);69 }70 71 /*72 * Wipe and free a struct oath_key73 */74 52 void 75 53 oath_key_free(struct oath_key *key) 76 54 { 55 int mapped, locked; 77 56 78 57 if (key != NULL) { 58 mapped = key->mapped; 59 locked = key->locked; 79 60 memset(key, 0, sizeof *key); 80 free(key); 61 if (mapped) { 62 if (locked) 63 munlock(key, sizeof *key); 64 munmap(key, sizeof *key); 65 } else { 66 free(key); 67 } 81 68 } 82 69 } 83 70 84 /* 85 * Allocate a struct oath_key and populate it from a Google Authenticator 86 * otpauth URI 71 /** 72 * The =oath_key_free function wipes and frees an OATH key structure which 73 * was previously allocated using the =oath_key_alloc function. 74 * 75 * >oath_key_alloc 76 * 77 * AUTHOR UIO 87 78 */ 88 struct oath_key *89 oath_key_from_uri(const char *uri)90 {91 struct oath_key *key;92 const char *p, *q, *r;93 uintmax_t n;94 char *e;95 96 if ((key = oath_key_alloc()) == NULL)97 return (NULL);98 99 /* check method */100 p = uri;101 if (strlcmp("otpauth://", p, 10) != 0)102 goto invalid;103 p += 10;104 105 /* check mode (hotp = event, totp = time-sync) */106 if ((q = strchr(p, '/')) == NULL)107 goto invalid;108 if (strlcmp("hotp", p, q - p) == 0) {109 key->mode = om_hotp;110 } else if (strlcmp("totp", p, q - p) == 0) {111 key->mode = om_totp;112 } else {113 goto invalid;114 }115 p = q + 1;116 117 /* extract label */118 if ((q = strchr(p, '?')) == NULL)119 goto invalid;120 if ((key->labellen = q - p + 1) > sizeof key->label)121 goto invalid;122 memcpy(key->label, p, q - p);123 key->label[q - p] = '\0';124 p = q + 1;125 126 /* extract parameters */127 key->counter = UINT64_MAX;128 while (*p != '\0') {129 if ((q = strchr(p, '=')) == NULL)130 goto invalid;131 q = q + 1;132 if ((r = strchr(p, '&')) == NULL)133 r = strchr(p, '\0');134 if (r < q)135 /* & before = */136 goto invalid;137 /* p points to key, q points to value, r points to & or NUL */138 if (strlcmp("secret=", p, q - p) == 0) {139 if (key->keylen != 0)140 /* dupe */141 goto invalid;142 key->keylen = sizeof key->key;143 if (base32_dec(q, r - q, key->key, &key->keylen) != 0)144 goto invalid;145 if (base32_enclen(key->keylen) != (size_t)(r - q))146 goto invalid;147 } else if (strlcmp("algorithm=", p, q - p) == 0) {148 if (key->hash != oh_undef)149 /* dupe */150 goto invalid;151 if (strlcmp("SHA1", q, r - q) == 0)152 key->hash = oh_sha1;153 else if (strlcmp("SHA256", q, r - q) == 0)154 key->hash = oh_sha256;155 else if (strlcmp("SHA512", q, r - q) == 0)156 key->hash = oh_sha512;157 else if (strlcmp("MD5", q, r - q) == 0)158 key->hash = oh_md5;159 else160 goto invalid;161 } else if (strlcmp("digits=", p, q - p) == 0) {162 if (key->digits != 0)163 /* dupe */164 goto invalid;165 /* only 6 or 8 */166 if (r - q != 1 || (*q != '6' && *q != '8'))167 goto invalid;168 key->digits = *q - '0';169 } else if (strlcmp("counter=", p, q - p) == 0) {170 if (key->counter != UINT64_MAX)171 /* dupe */172 goto invalid;173 n = strtoumax(q, &e, 10);174 if (e != r || n >= UINT64_MAX)175 goto invalid;176 key->counter = (uint64_t)n;177 } else if (strlcmp("period=", p, q - p) == 0) {178 if (key->timestep != 0)179 /* dupe */180 goto invalid;181 n = strtoumax(q, &e, 10);182 if (e != r || n > OATH_MAX_TIMESTEP)183 goto invalid;184 key->timestep = n;185 } else {186 goto invalid;187 }188 /* final parameter? */189 if (*r == '\0')190 break;191 /* skip & and continue */192 p = r + 1;193 }194 195 /* sanity checks and default values */196 if (key->mode == om_hotp) {197 if (key->timestep != 0)198 goto invalid;199 if (key->counter == UINTMAX_MAX)200 key->counter = 0;201 } else if (key->mode == om_totp) {202 if (key->counter != UINTMAX_MAX)203 goto invalid;204 if (key->timestep == 0)205 key->timestep = OATH_DEF_TIMESTEP;206 } else {207 /* unreachable */208 oath_key_free(key);209 return (NULL);210 }211 if (key->hash == oh_undef)212 key->hash = oh_sha1;213 if (key->digits == 0)214 key->digits = 6;215 if (key->keylen == 0)216 goto invalid;217 return (key);218 219 invalid:220 openpam_log(PAM_LOG_NOTICE, "invalid OATH URI: %s", uri);221 oath_key_free(key);222 return (NULL);223 }224 225 struct oath_key *226 oath_key_from_file(const char *filename)227 {228 struct oath_key *key;229 FILE *f;230 char *line;231 size_t len;232 233 if ((f = fopen(filename, "r")) == NULL)234 return (NULL);235 /* get first non-empty non-comment line */236 line = openpam_readline(f, NULL, &len);237 if (strlcmp("otpauth://", line, len) == 0) {238 key = oath_key_from_uri(line);239 } else {240 openpam_log(PAM_LOG_ERROR,241 "unrecognized key file format: %s", filename);242 key = NULL;243 }244 fclose(f);245 return (key);246 }247 248 char *249 oath_key_to_uri(const struct oath_key *key)250 {251 const char *hash;252 char *tmp, *uri;253 size_t kslen, urilen;254 255 switch (key->hash) {256 case oh_sha1:257 hash = "SHA1";258 break;259 case oh_sha256:260 hash = "SHA256";261 break;262 case oh_sha512:263 hash = "SHA512";264 break;265 case oh_md5:266 hash = "MD5";267 break;268 default:269 return (NULL);270 }271 272 if (key->mode == om_hotp) {273 urilen = asprintf(&uri, "otpauth://"274 "%s/%s?algorithm=%s&digits=%d&counter=%ju&secret=",275 "hotp", key->label, hash, key->digits,276 (uintmax_t)key->counter);277 } else if (key->mode == om_totp) {278 urilen = asprintf(&uri, "otpauth://"279 "%s/%s?algorithm=%s&digits=%d&period=%u&secret=",280 "totp", key->label, hash, key->digits, key->timestep);281 } else {282 /* unreachable */283 return (NULL);284 }285 286 /* compute length of base32-encoded key and append it */287 kslen = base32_enclen(key->keylen) + 1;288 if ((tmp = realloc(uri, urilen + kslen)) == NULL) {289 free(uri);290 return (NULL);291 }292 uri = tmp;293 if (base32_enc(key->key, key->keylen, uri + urilen, &kslen) != 0) {294 free(uri);295 return (NULL);296 }297 298 return (uri);299 }300 301 struct oath_key *302 oath_dummy_key(enum oath_mode mode, enum oath_hash hash, unsigned int digits)303 {304 struct oath_key *key;305 306 if ((key = oath_key_alloc()) == NULL)307 return (NULL);308 key->mode = mode;309 key->digits = digits;310 key->counter = 0;311 key->timestep = 30;312 key->hash = hash;313 strcpy(key->label, "oath-dummy-key");314 key->labellen = strlen(key->label);315 key->keylen = sizeof key->key;316 return (key);317 }
Note: See TracChangeset
for help on using the changeset viewer.