source: openpam/trunk/lib/liboath/oath_key_from_uri.c @ 785

Last change on this file since 785 was 785, checked in by Dag-Erling Smørgrav, 7 years ago

Missing word

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id
File size: 5.8 KB
Line 
1/*-
2 * Copyright (c) 2013-2014 Universitetet i Oslo
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 *    notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 *    notice, this list of conditions and the following disclaimer in the
12 *    documentation and/or other materials provided with the distribution.
13 * 3. The name of the author may not be used to endorse or promote
14 *    products derived from this software without specific prior written
15 *    permission.
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 * $Id: oath_key_from_uri.c 785 2014-03-10 15:37:38Z des $
30 */
31
32#ifdef HAVE_CONFIG_H
33# include "config.h"
34#endif
35
36#include <sys/types.h>
37
38#include <inttypes.h>
39#include <string.h>
40
41#include <security/pam_appl.h>
42#include <security/openpam.h>
43
44#include "openpam_strlcmp.h"
45
46#include <security/oath.h>
47
48/*
49 * OATH
50 *
51 * Creates an OATH key from a Google otpauth URI
52 */
53
54struct oath_key *
55oath_key_from_uri(const char *uri)
56{
57        struct oath_key *key;
58        const char *p, *q, *r;
59        uintmax_t n;
60        char *e;
61
62        if ((key = oath_key_alloc()) == NULL)
63                return (NULL);
64
65        /* check method */
66        p = uri;
67        if (strlcmp("otpauth://", p, 10) != 0)
68                goto invalid;
69        p += 10;
70
71        /* check mode (hotp = event, totp = time-sync) */
72        if ((q = strchr(p, '/')) == NULL)
73                goto invalid;
74        if (strlcmp("hotp", p, q - p) == 0) {
75                key->mode = om_hotp;
76        } else if (strlcmp("totp", p, q - p) == 0) {
77                key->mode = om_totp;
78        } else {
79                goto invalid;
80        }
81        p = q + 1;
82
83        /* extract label */
84        if ((q = strchr(p, '?')) == NULL)
85                goto invalid;
86        key->labellen = oath_uri_decode(p, q - p, key->label,
87            sizeof key->label);
88        if (key->labellen > sizeof key->label)
89                goto invalid;
90        p = q + 1;
91
92        /* extract parameters */
93        key->counter = UINT64_MAX;
94        key->lastused = UINT64_MAX;
95        while (*p != '\0') {
96                if ((q = strchr(p, '=')) == NULL)
97                        goto invalid;
98                q = q + 1;
99                if ((r = strchr(p, '&')) == NULL)
100                        r = strchr(p, '\0');
101                if (r < q)
102                        /* & before = */
103                        goto invalid;
104                /* p points to key, q points to value, r points to & or NUL */
105                if (strlcmp("secret=", p, q - p) == 0) {
106                        if (key->keylen != 0)
107                                /* dupe */
108                                goto invalid;
109                        key->keylen = sizeof key->key;
110                        if (base32_dec(q, r - q, (char *)key->key, &key->keylen) != 0)
111                                goto invalid;
112                        if (base32_enclen(key->keylen) != (size_t)(r - q))
113                                goto invalid;
114                } else if (strlcmp("algorithm=", p, q - p) == 0) {
115                        if (key->hash != oh_undef)
116                                /* dupe */
117                                goto invalid;
118                        if (strlcmp("SHA1", q, r - q) == 0)
119                                key->hash = oh_sha1;
120                        else if (strlcmp("SHA256", q, r - q) == 0)
121                                key->hash = oh_sha256;
122                        else if (strlcmp("SHA512", q, r - q) == 0)
123                                key->hash = oh_sha512;
124                        else if (strlcmp("MD5", q, r - q) == 0)
125                                key->hash = oh_md5;
126                        else
127                                goto invalid;
128                } else if (strlcmp("digits=", p, q - p) == 0) {
129                        if (key->digits != 0)
130                                /* dupe */
131                                goto invalid;
132                        /* only 6 or 8 */
133                        if (r - q != 1 || (*q != '6' && *q != '8'))
134                                goto invalid;
135                        key->digits = *q - '0';
136                } else if (strlcmp("counter=", p, q - p) == 0) {
137                        if (key->counter != UINT64_MAX)
138                                /* dupe */
139                                goto invalid;
140                        n = strtoumax(q, &e, 10);
141                        if (e != r || n >= UINT64_MAX)
142                                goto invalid;
143                        key->counter = (uint64_t)n;
144                } else if (strlcmp("lastused=", p, q - p) == 0) {
145                        if (key->lastused != UINT64_MAX)
146                                /* dupe */
147                                goto invalid;
148                        n = strtoumax(q, &e, 10);
149                        if (e != r || n >= UINT64_MAX)
150                                goto invalid;
151                        key->lastused = (uint64_t)n;
152                } else if (strlcmp("period=", p, q - p) == 0) {
153                        if (key->timestep != 0)
154                                /* dupe */
155                                goto invalid;
156                        n = strtoumax(q, &e, 10);
157                        if (e != r || n > OATH_MAX_TIMESTEP)
158                                goto invalid;
159                        key->timestep = n;
160                } else if (strlcmp("issuer=", p, q - p) == 0) {
161                        // noop for now
162                } else {
163                        goto invalid;
164                }
165                /* final parameter? */
166                if (*r == '\0')
167                        break;
168                /* skip & and continue */
169                p = r + 1;
170        }
171
172        /* sanity checks and default values */
173        if (key->mode == om_hotp) {
174                if (key->counter == UINT64_MAX)
175                        key->counter = 0;
176                if (key->timestep != 0)
177                        goto invalid;
178                if (key->lastused != UINT64_MAX)
179                        goto invalid;
180        } else if (key->mode == om_totp) {
181                if (key->counter != UINT64_MAX)
182                        goto invalid;
183                if (key->timestep == 0)
184                        key->timestep = OATH_DEF_TIMESTEP;
185                if (key->lastused == UINT64_MAX)
186                        key->lastused = 0;
187        } else {
188                /* unreachable */
189                oath_key_free(key);
190                return (NULL);
191        }
192        if (key->hash == oh_undef)
193                key->hash = oh_sha1;
194        if (key->digits == 0)
195                key->digits = 6;
196        if (key->keylen == 0)
197                goto invalid;
198        return (key);
199
200invalid:
201        openpam_log(PAM_LOG_NOTICE, "invalid OATH URI: %s", uri);
202        oath_key_free(key);
203        return (NULL);
204}
205
206/**
207 * The =oath_key_from_uri function parses a Google otpauth URI into a key
208 * structure.
209 *
210 * The =uri parameter points to a NUL-terminated string containing the
211 * URI.
212 *
213 * Keys created with =oath_key_from_uri must be freed using
214 * =oath_key_free.
215 *
216 * >oath_key_alloc
217 * >oath_key_free
218 * >oath_key_to_uri
219 *
220 * REFERENCES
221 *
222 * https://code.google.com/p/google-authenticator/wiki/KeyUriFormat
223 *
224 * AUTHOR UIO
225 */
Note: See TracBrowser for help on using the repository browser.