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