]> git.ipfire.org Git - people/ms/strongswan.git/blob - src/pki/pki.c
pki: Provide a fallback if strptime() not supported
[people/ms/strongswan.git] / src / pki / pki.c
1 /*
2 * Copyright (C) 2009 Martin Willi
3 * Hochschule fuer Technik Rapperswil
4 *
5 * This program is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License as published by the
7 * Free Software Foundation; either version 2 of the License, or (at your
8 * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
9 *
10 * This program is distributed in the hope that it will be useful, but
11 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
12 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
13 * for more details.
14 */
15
16 #define _GNU_SOURCE
17 #include "command.h"
18 #include "pki.h"
19
20 #include <time.h>
21 #include <unistd.h>
22 #include <fcntl.h>
23
24 #include <utils/debug.h>
25 #include <credentials/sets/callback_cred.h>
26
27 /**
28 * Convert a form string to a encoding type
29 */
30 bool get_form(char *form, cred_encoding_type_t *enc, credential_type_t type)
31 {
32 if (streq(form, "der"))
33 {
34 switch (type)
35 {
36 case CRED_CERTIFICATE:
37 *enc = CERT_ASN1_DER;
38 return TRUE;
39 case CRED_PRIVATE_KEY:
40 *enc = PRIVKEY_ASN1_DER;
41 return TRUE;
42 case CRED_PUBLIC_KEY:
43 /* der encoded keys usually contain the complete
44 * SubjectPublicKeyInfo */
45 *enc = PUBKEY_SPKI_ASN1_DER;
46 return TRUE;
47 default:
48 return FALSE;
49 }
50 }
51 else if (streq(form, "pem"))
52 {
53 switch (type)
54 {
55 case CRED_CERTIFICATE:
56 *enc = CERT_PEM;
57 return TRUE;
58 case CRED_PRIVATE_KEY:
59 *enc = PRIVKEY_PEM;
60 return TRUE;
61 case CRED_PUBLIC_KEY:
62 *enc = PUBKEY_PEM;
63 return TRUE;
64 default:
65 return FALSE;
66 }
67 }
68 else if (streq(form, "pgp"))
69 {
70 switch (type)
71 {
72 case CRED_PRIVATE_KEY:
73 *enc = PRIVKEY_PGP;
74 return TRUE;
75 case CRED_PUBLIC_KEY:
76 *enc = PUBKEY_PGP;
77 return TRUE;
78 default:
79 return FALSE;
80 }
81 }
82 else if (streq(form, "dnskey"))
83 {
84 switch (type)
85 {
86 case CRED_PUBLIC_KEY:
87 *enc = PUBKEY_DNSKEY;
88 return TRUE;
89 default:
90 return FALSE;
91 }
92 }
93 else if (streq(form, "sshkey"))
94 {
95 switch (type)
96 {
97 case CRED_PUBLIC_KEY:
98 *enc = PUBKEY_SSHKEY;
99 return TRUE;
100 default:
101 return FALSE;
102 }
103 }
104 return FALSE;
105 }
106
107 /**
108 * Convert a time string to struct tm using strptime format
109 */
110 static bool convert_time(char *str, char *format, struct tm *tm)
111 {
112 #ifdef HAVE_STRPTIME
113
114 char *end;
115
116 if (!format)
117 {
118 format = "%d.%m.%y %T";
119 }
120
121 end = strptime(str, format, tm);
122 if (end == NULL || *end != '\0')
123 {
124 return FALSE;
125 }
126 return TRUE;
127
128 #else /* !HAVE_STRPTIME */
129
130 if (format)
131 {
132 fprintf(stderr, "custom datetime string format not supported\n");
133 return FALSE;
134 }
135
136 if (sscanf(str, "%d.%d.%d %d:%d:%d",
137 &tm->tm_mday, &tm->tm_mon, &tm->tm_year,
138 &tm->tm_hour, &tm->tm_min, &tm->tm_sec) != 6)
139 {
140 return FALSE;
141 }
142 /* strptime() interprets two-digit years > 68 as 19xx, do the same here.
143 * mktime() expects years based on 1900 */
144 if (tm->tm_year <= 68)
145 {
146 tm->tm_year += 100;
147 }
148 else if (tm->tm_year >= 1900)
149 { /* looks like four digits? */
150 tm->tm_year -= 1900;
151 }
152 /* month is specified from 0-11 */
153 tm->tm_mon--;
154 /* automatically detect daylight saving time */
155 tm->tm_isdst = -1;
156 return TRUE;
157
158 #endif /* !HAVE_STRPTIME */
159 }
160
161 /**
162 * See header
163 */
164 bool calculate_lifetime(char *format, char *nbstr, char *nastr, time_t span,
165 time_t *nb, time_t *na)
166 {
167 struct tm tm;
168 time_t now;
169
170 now = time(NULL);
171
172 localtime_r(&now, &tm);
173 if (nbstr)
174 {
175 if (!convert_time(nbstr, format, &tm))
176 {
177 return FALSE;
178 }
179 }
180 *nb = mktime(&tm);
181 if (*nb == -1)
182 {
183 return FALSE;
184 }
185
186 localtime_r(&now, &tm);
187 if (nastr)
188 {
189 if (!convert_time(nastr, format, &tm))
190 {
191 return FALSE;
192 }
193 }
194 *na = mktime(&tm);
195 if (*na == -1)
196 {
197 return FALSE;
198 }
199
200 if (!nbstr && nastr)
201 {
202 *nb = *na - span;
203 }
204 else if (!nastr)
205 {
206 *na = *nb + span;
207 }
208 return TRUE;
209 }
210
211 /**
212 * Set output file mode appropriate for credential encoding form on Windows
213 */
214 void set_file_mode(FILE *stream, cred_encoding_type_t enc)
215 {
216 #ifdef WIN32
217 int fd;
218
219 switch (enc)
220 {
221 case CERT_PEM:
222 case PRIVKEY_PEM:
223 case PUBKEY_PEM:
224 /* keep default text mode */
225 return;
226 default:
227 /* switch to binary mode */
228 break;
229 }
230 fd = fileno(stream);
231 if (fd != -1)
232 {
233 _setmode(fd, _O_BINARY);
234 }
235 #endif
236 }
237
238 /**
239 * Callback credential set pki uses
240 */
241 static callback_cred_t *cb_set;
242
243 /**
244 * Callback function to receive credentials
245 */
246 static shared_key_t* cb(void *data, shared_key_type_t type,
247 identification_t *me, identification_t *other,
248 id_match_t *match_me, id_match_t *match_other)
249 {
250 char buf[64], *label, *secret = NULL;
251
252 switch (type)
253 {
254 case SHARED_PIN:
255 label = "Smartcard PIN";
256 break;
257 case SHARED_PRIVATE_KEY_PASS:
258 label = "Private key passphrase";
259 break;
260 default:
261 return NULL;
262 }
263 snprintf(buf, sizeof(buf), "%s: ", label);
264 #ifdef HAVE_GETPASS
265 secret = getpass(buf);
266 #endif
267 if (secret && strlen(secret))
268 {
269 if (match_me)
270 {
271 *match_me = ID_MATCH_PERFECT;
272 }
273 if (match_other)
274 {
275 *match_other = ID_MATCH_NONE;
276 }
277 return shared_key_create(type,
278 chunk_clone(chunk_create(secret, strlen(secret))));
279 }
280 return NULL;
281 }
282
283 /**
284 * Register PIN/Passphrase callback function
285 */
286 static void add_callback()
287 {
288 cb_set = callback_cred_create_shared(cb, NULL);
289 lib->credmgr->add_set(lib->credmgr, &cb_set->set);
290 }
291
292 /**
293 * Unregister PIN/Passphrase callback function
294 */
295 static void remove_callback()
296 {
297 lib->credmgr->remove_set(lib->credmgr, &cb_set->set);
298 cb_set->destroy(cb_set);
299 }
300
301 /**
302 * Library initialization and operation parsing
303 */
304 int main(int argc, char *argv[])
305 {
306 atexit(library_deinit);
307 if (!library_init(NULL, "pki"))
308 {
309 exit(SS_RC_LIBSTRONGSWAN_INTEGRITY);
310 }
311 if (lib->integrity &&
312 !lib->integrity->check_file(lib->integrity, "pki", argv[0]))
313 {
314 fprintf(stderr, "integrity check of pki failed\n");
315 exit(SS_RC_DAEMON_INTEGRITY);
316 }
317 if (!lib->plugins->load(lib->plugins,
318 lib->settings->get_str(lib->settings, "pki.load", PLUGINS)))
319 {
320 exit(SS_RC_INITIALIZATION_FAILED);
321 }
322
323 add_callback();
324 atexit(remove_callback);
325 return command_dispatch(argc, argv);
326 }