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

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

Switch from uint8_t to char.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id
File size: 5.7 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 772 2014-03-09 11:45:05Z 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 {
161                        goto invalid;
162                }
163                /* final parameter? */
164                if (*r == '\0')
165                        break;
166                /* skip & and continue */
167                p = r + 1;
168        }
169
170        /* sanity checks and default values */
171        if (key->mode == om_hotp) {
172                if (key->counter == UINT64_MAX)
173                        key->counter = 0;
174                if (key->timestep != 0)
175                        goto invalid;
176                if (key->lastused != UINT64_MAX)
177                        goto invalid;
178        } else if (key->mode == om_totp) {
179                if (key->counter != UINT64_MAX)
180                        goto invalid;
181                if (key->timestep == 0)
182                        key->timestep = OATH_DEF_TIMESTEP;
183                if (key->lastused == UINT64_MAX)
184                        key->lastused = 0;
185        } else {
186                /* unreachable */
187                oath_key_free(key);
188                return (NULL);
189        }
190        if (key->hash == oh_undef)
191                key->hash = oh_sha1;
192        if (key->digits == 0)
193                key->digits = 6;
194        if (key->keylen == 0)
195                goto invalid;
196        return (key);
197
198invalid:
199        openpam_log(PAM_LOG_NOTICE, "invalid OATH URI: %s", uri);
200        oath_key_free(key);
201        return (NULL);
202}
203
204/**
205 * The =oath_key_from_uri parses a Google otpauth URI into a key
206 * structure.
207 *
208 * The =uri parameter points to a NUL-terminated string containing the
209 * URI.
210 *
211 * Keys created with =oath_key_from_uri must be freed using
212 * =oath_key_free.
213 *
214 * >oath_key_alloc
215 * >oath_key_free
216 * >oath_key_to_uri
217 *
218 * REFERENCES
219 *
220 * https://code.google.com/p/google-authenticator/wiki/KeyUriFormat
221 *
222 * AUTHOR UIO
223 */
Note: See TracBrowser for help on using the repository browser.