Changeset 689 in openpam for trunk/lib


Ignore:
Timestamp:
Jul 12, 2013, 10:47:14 AM (7 years ago)
Author:
Dag-Erling Smørgrav
Message:

Factor out oath_key_{alloc,free}() and implement wiring / locking.

Location:
trunk/lib/liboath
Files:
2 edited
2 copied

Legend:

Unmodified
Added
Removed
  • trunk/lib/liboath/Makefile.am

    r654 r689  
    1010        oath_hotp.c \
    1111        oath_totp.c \
     12        oath_key_alloc.c \
     13        oath_key_free.c \
    1214        oath_key.c
    1315
  • trunk/lib/liboath/oath_key.c

    r679 r689  
    3939#include <inttypes.h>
    4040#include <limits.h>
    41 #include <stdint.h>
    4241#include <stdio.h>
    4342#include <stdlib.h>
     
    5150
    5251#include <security/oath.h>
    53 
    54 /*
    55  * Allocate a struct oath_key with sufficient additional space for the
    56  * 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_key
    73  */
    74 void
    75 oath_key_free(struct oath_key *key)
    76 {
    77 
    78         if (key != NULL) {
    79                 memset(key, 0, sizeof *key);
    80                 free(key);
    81         }
    82 }
    8352
    8453/*
  • trunk/lib/liboath/oath_key_alloc.c

    r680 r689  
    3434#endif
    3535
    36 #include <sys/types.h>
     36#include <sys/mman.h>
    3737
    38 #include <errno.h>
    39 #include <inttypes.h>
    40 #include <limits.h>
    4138#include <stdint.h>
    42 #include <stdio.h>
    4339#include <stdlib.h>
    4440#include <string.h>
     
    4642#include <security/pam_appl.h>
    4743#include <security/openpam.h>
    48 
    49 #include "openpam_asprintf.h"
    50 #include "openpam_strlcmp.h"
    51 
    5244#include <security/oath.h>
    5345
    5446/*
    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
    5750 */
     51
    5852struct oath_key *
    5953oath_key_alloc(void)
     
    6155        struct oath_key *key;
    6256
    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");
    6667        }
    67         /* XXX should try to wire */
    6868        return (key);
    6969}
    7070
    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
    7380 */
    74 void
    75 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 Authenticator
    86  * otpauth URI
    87  */
    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                         else
    160                                 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  
    3434#endif
    3535
    36 #include <sys/types.h>
     36#include <sys/mman.h>
    3737
    38 #include <errno.h>
    39 #include <inttypes.h>
    40 #include <limits.h>
    4138#include <stdint.h>
    42 #include <stdio.h>
    4339#include <stdlib.h>
    4440#include <string.h>
     
    4642#include <security/pam_appl.h>
    4743#include <security/openpam.h>
    48 
    49 #include "openpam_asprintf.h"
    50 #include "openpam_strlcmp.h"
    51 
    5244#include <security/oath.h>
    5345
    5446/*
    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
    5750 */
    58 struct oath_key *
    59 oath_key_alloc(void)
    60 {
    61         struct oath_key *key;
    6251
    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_key
    73  */
    7452void
    7553oath_key_free(struct oath_key *key)
    7654{
     55        int mapped, locked;
    7756
    7857        if (key != NULL) {
     58                mapped = key->mapped;
     59                locked = key->locked;
    7960                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                }
    8168        }
    8269}
    8370
    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
    8778 */
    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                         else
    160                                 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.