1 /*
2  * stoken.h - public libstoken library interface
3  *
4  * Copyright 2012 Kevin Cernekee <cernekee@gmail.com>
5  *
6  * This program is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2.1 of the License, or (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this program; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
19  */
20 
21 #ifndef __STOKEN_H__
22 #define __STOKEN_H__
23 
24 #include <errno.h>
25 #include <stdlib.h>
26 #include <time.h>
27 
28 #ifdef __cplusplus
29 extern "C" {
30 #endif
31 
32 #define STOKEN_API_VER_MAJOR	1
33 #define STOKEN_API_VER_MINOR	3
34 
35 /* Before API version 1.3 (stoken 0.8) this macro didn't exist.
36  * Somewhat ironic, that the API version check itself needs to be
37  * conditionally used depending on the API version. A very simple way
38  * for users to handle this with an approximately correct answer is
39  *   #include <stoken.h>
40  *   #ifndef STOKEN_CHECK_VER
41  *   #define STOKEN_CHECK_VER(x,y) 0
42  *   #endif
43  */
44 #define STOKEN_CHECK_VER(maj, min) \
45 	(STOKEN_API_VER_MAJOR > (maj) || \
46 	(STOKEN_API_VER_MAJOR == (maj) && \
47 	 STOKEN_API_VER_MINOR >= (min)))
48 
49 #define STOKEN_MAX_TOKENCODE	8
50 
51 #if defined(_WIN32) && defined(LIBSTOKEN_BUILD)
52 #define STOKEN_EXPORT		__declspec(dllexport)
53 #elif defined(_WIN32)
54 #define STOKEN_EXPORT		__declspec(dllimport)
55 #else
56 #define STOKEN_EXPORT
57 #endif
58 
59 struct stoken_ctx;
60 
61 struct stoken_info {
62 	char			serial[16];
63 	time_t			exp_date;
64 	int			interval;
65 	int			token_version;
66 	int			uses_pin;
67 };
68 
69 struct stoken_guid {
70 	const char		*tag;
71 	const char		*long_name;
72 	const char		*guid;
73 };
74 
75 /*
76  * Create/destroy library context.
77  * stoken_new() returns NULL on error.
78  */
79 STOKEN_EXPORT struct stoken_ctx *stoken_new(void);
80 STOKEN_EXPORT void stoken_destroy(struct stoken_ctx *ctx);
81 
82 /*
83  * Load a token from an existing .stokenrc file (PATH can be NULL to use
84  * $HOME/.stokenrc).
85  *
86  * Return values:
87  *
88  *   0:       success; token is now stored in CTX
89  *   -ENOENT: missing input file
90  *   -EINVAL: invalid input file format
91  *   -EIO:    any other failure (e.g. ran out of memory)
92  */
93 STOKEN_EXPORT int stoken_import_rcfile(struct stoken_ctx *ctx,
94 				       const char *path);
95 
96 /*
97  * Parse a token string (nominally a string of ~71 digits, starting with
98  * '1' or '2').
99  *
100  * Return values:
101  *
102  *   0:       success; token is now stored in CTX
103  *   -EINVAL: invalid input string format
104  *   -EIO:    any other failure (e.g. ran out of memory)
105  */
106 STOKEN_EXPORT int stoken_import_string(struct stoken_ctx *ctx,
107 				       const char *token_string);
108 
109 /*
110  * Retrieve metadata for the currently imported token.  This returns a
111  * callee-allocated, caller-freed struct, which may grow larger in the future.
112  *
113  * In general this should be called after stoken_decrypt_seed(), as
114  * most of the token metadata is encrypted with the devid and/or password on
115  * v3 tokens.
116  *
117  * Return values:
118  *
119  *   ptr:     success
120  *   NULL:    any failure (e.g. ran out of memory)
121  */
122 STOKEN_EXPORT struct stoken_info *stoken_get_info(struct stoken_ctx *ctx);
123 
124 /*
125  * Set *MIN_PIN and *MAX_PIN to reflect the valid range of PIN lengths
126  * (e.g. 4-8).
127  */
128 STOKEN_EXPORT void stoken_pin_range(struct stoken_ctx *ctx,
129 				    int *min_pin,
130 				    int *max_pin);
131 
132 /*
133  * Returns nonzero if the token in CTX requires a PIN, and doesn't have one
134  * saved (i.e. you need to prompt for it).  stoken_info->uses_pin returns
135  * nonzero if a PIN is used in the calculation.  If stoken_info->uses_pin is
136  * 0, a PIN is not needed to generate the tokencode but you may need to
137  * request and concatenate a PIN in order to log in to a protected resource:
138  * PASSCODE = PIN + TOKENCODE
139  */
140 STOKEN_EXPORT int stoken_pin_required(struct stoken_ctx *ctx);
141 
142 /* returns nonzero if the token in CTX needs a password to decrypt the seed */
143 STOKEN_EXPORT int stoken_pass_required(struct stoken_ctx *ctx);
144 
145 /* returns nonzero if the token in CTX needs a device ID to decrypt the seed */
146 STOKEN_EXPORT int stoken_devid_required(struct stoken_ctx *ctx);
147 
148 /*
149  * Check the PIN for proper format.  This does not validate whether the PIN
150  * matches the PIN on file for the user's account; only the server knows that.
151  *
152  * Return values:
153  *
154  *   0:       success
155  *   -EINVAL: invalid format
156  */
157 STOKEN_EXPORT int stoken_check_pin(struct stoken_ctx *ctx, const char *pin);
158 
159 /*
160  * Obtain the list of known "class GUIDs" used to bind a token to a specific
161  * type of device (e.g. iPhone).
162  */
163 STOKEN_EXPORT const struct stoken_guid *stoken_get_guid_list(void);
164 
165 /*
166  * Check the device ID by performing a partial seed decrypt.  This helps
167  * callers provide better user feedback after a stoken_decrypt_seed() failure.
168  *
169  * Return values:
170  *
171  *   0:       success
172  *   -EINVAL: DEVID MAC failed
173  *   -EIO:    any other failure (e.g. ran out of memory)
174  */
175 STOKEN_EXPORT int stoken_check_devid(struct stoken_ctx *ctx,
176 				     const char *devid);
177 
178 /*
179  * Try to decrypt the seed stored in CTX, and compare the MAC to see if
180  * decryption was successful.
181  *
182  * PASS may be NULL if stoken_needs_pass() == 0
183  * DEVID may be NULL if stoken_needs_devid() == 0
184  *
185  * Return values:
186  *
187  *   0:       success
188  *   -EINVAL: MAC failed (PASS or DEVID is probably incorrect)
189  *   -EIO:    any other failure (e.g. ran out of memory)
190  */
191 STOKEN_EXPORT int stoken_decrypt_seed(struct stoken_ctx *ctx,
192 				      const char *pass,
193 				      const char *devid);
194 
195 /*
196  * Generate a new token string for the previously-decrypted seed stored
197  * in CTX.  PASS and DEVID may be NULL.  The returned string must be freed
198  * by the caller.
199  *
200  * Return values:
201  *
202  *   ptr:     on success, a pointer to a new string
203  *   NULL:    on failure
204  */
205 STOKEN_EXPORT char *stoken_encrypt_seed(struct stoken_ctx *ctx,
206 					const char *pass,
207 					const char *devid);
208 
209 /*
210  * Generate a tokencode from the decrypted seed, for UNIX time WHEN.
211  * OUT is allocated by the caller, and must be able to store at least
212  * (STOKEN_MAX_TOKENCODE + 1) bytes.
213  *
214  * This can be called over and over again, as needed.
215  *
216  * If stoken_pin_required() returns 0, PIN may be NULL.  If PIN is not
217  * NULL and the user stored a PIN in ~/.stokenrc, the PIN string passed
218  * into this function will override the stored PIN.  This will affect
219  * subsequent calls to stoken_compute_tokencode() but the change will not
220  * be stored on disk.
221  *
222  * Return values:
223  *
224  *   0:       success
225  *   -EINVAL: invalid PIN format
226  *   -EIO:    general failure
227  */
228 STOKEN_EXPORT int stoken_compute_tokencode(struct stoken_ctx *ctx,
229 					   time_t when,
230 					   const char *pin,
231 					   char *out);
232 
233 /*
234  * Inject a space in the middle of the code, e.g. "1234 5678".
235  * Typical libstoken users would use the formatted tokencode for display
236  * purposes only, and use the unformatted tokencode for "copy to clipboard",
237  * pasting into login forms, etc.
238  *
239  * The returned string must be freed by the caller.  Returns NULL on malloc
240  * failure.
241  */
242 STOKEN_EXPORT char *stoken_format_tokencode(const char *tokencode);
243 
244 #ifdef __cplusplus
245 }
246 #endif
247 
248 #endif /* !__STOKEN_H__ */
249