1 /***************************************************************************
2 openssl_cert.c - description
3 -------------------
4 begin : Tue May 14 2002
5 copyright : (C) 2002 by ARRL
6 author : Jon Bloom
7 email : jbloom@arrl.org
8 revision : $Id$
9 ***************************************************************************/
10
11 /* Routines to massage X.509 certs for tQSL. See openssl_cert.h for overview */
12
13 /* 2004-04-10 Fixed tqsl_add_bag_attribute error for OpenSSL > 0.96
14 (Thanks to Kenji, JJ1BDX for the fix)
15 */
16
17 /* Portions liberally copied from OpenSSL's apps source code */
18
19 /* ====================================================================
20 * Copyright (c) 1998-2001 The OpenSSL Project. All rights reserved.
21 *
22 * Redistribution and use in source and binary forms, with or without
23 * modification, are permitted provided that the following conditions
24 * are met:
25 *
26 * 1. Redistributions of source code must retain the above copyright
27 * notice, this list of conditions and the following disclaimer.
28 *
29 * 2. Redistributions in binary form must reproduce the above copyright
30 * notice, this list of conditions and the following disclaimer in
31 * the documentation and/or other materials provided with the
32 * distribution.
33 *
34 * 3. All advertising materials mentioning features or use of this
35 * software must display the following acknowledgment:
36 * "This product includes software developed by the OpenSSL Project
37 * for use in the OpenSSL Toolkit. (http://www.openssl.org/)"
38 *
39 * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
40 * endorse or promote products derived from this software without
41 * prior written permission. For written permission, please contact
42 * openssl-core@openssl.org.
43 *
44 * 5. Products derived from this software may not be called "OpenSSL"
45 * nor may "OpenSSL" appear in their names without prior written
46 * permission of the OpenSSL Project.
47 *
48 * 6. Redistributions of any form whatsoever must retain the following
49 * acknowledgment:
50 * "This product includes software developed by the OpenSSL Project
51 * for use in the OpenSSL Toolkit (http://www.openssl.org/)"
52 *
53 * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
54 * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
55 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
56 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR
57 * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
58 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
59 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
60 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
61 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
62 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
63 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
64 * OF THE POSSIBILITY OF SUCH DAMAGE.
65 * ====================================================================
66 *
67 * This product includes cryptographic software written by Eric Young
68 * (eay@cryptsoft.com). This product includes software written by Tim
69 * Hudson (tjh@cryptsoft.com).
70 *
71 */
72
73 /* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
74 * All rights reserved.
75 *
76 * This package is an SSL implementation written
77 * by Eric Young (eay@cryptsoft.com).
78 * The implementation was written so as to conform with Netscapes SSL.
79 *
80 * This library is free for commercial and non-commercial use as long as
81 * the following conditions are aheared to. The following conditions
82 * apply to all code found in this distribution, be it the RC4, RSA,
83 * lhash, DES, etc., code; not just the SSL code. The SSL documentation
84 * included with this distribution is covered by the same copyright terms
85 * except that the holder is Tim Hudson (tjh@cryptsoft.com).
86 *
87 * Copyright remains Eric Young's, and as such any Copyright notices in
88 * the code are not to be removed.
89 * If this package is used in a product, Eric Young should be given attribution
90 * as the author of the parts of the library used.
91 * This can be in the form of a textual message at program startup or
92 * in documentation (online or textual) provided with the package.
93 *
94 * Redistribution and use in source and binary forms, with or without
95 * modification, are permitted provided that the following conditions
96 * are met:
97 * 1. Redistributions of source code must retain the copyright
98 * notice, this list of conditions and the following disclaimer.
99 * 2. Redistributions in binary form must reproduce the above copyright
100 * notice, this list of conditions and the following disclaimer in the
101 * documentation and/or other materials provided with the distribution.
102 * 3. All advertising materials mentioning features or use of this software
103 * must display the following acknowledgement:
104 * "This product includes cryptographic software written by
105 * Eric Young (eay@cryptsoft.com)"
106 * The word 'cryptographic' can be left out if the rouines from the library
107 * being used are not cryptographic related :-).
108 * 4. If you include any Windows specific code (or a derivative thereof) from
109 * the apps directory (application code) you must include an acknowledgement:
110 * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
111 *
112 * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
113 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
114 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
115 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
116 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
117 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
118 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
119 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
120 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
121 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
122 * SUCH DAMAGE.
123 *
124 * The licence and distribution terms for any publically available version or
125 * derivative of this code cannot be changed. i.e. this code cannot simply be
126 * copied and put under another distribution licence
127 * [including the GNU Public Licence.]
128 */
129
130 #define OPENSSL_CERT_SOURCE
131
132 #define TQSLLIB_DEF
133
134
135 #include <sys/stat.h>
136 #include <sys/types.h>
137 #include <string.h>
138 #include <zlib.h>
139 #include <errno.h>
140 #include <ctype.h>
141 #include <stdlib.h>
142 #ifdef _WIN32
143 #include <direct.h>
144 #define MKDIR(x, y) _wmkdir(x)
145 #else
146 #define MKDIR(x, y) mkdir(x, y)
147 #include <unistd.h>
148 #include <dirent.h>
149 #endif
150 #include <openssl/err.h>
151 #include <openssl/pem.h>
152 #include <openssl/rand.h>
153 #undef X509_NAME //http://www.mail-archive.com/openssl-users@openssl.org/msg59116.html
154 #include <openssl/x509.h>
155 #include <openssl/x509v3.h>
156 #include <openssl/pkcs12.h>
157 #include <openssl/opensslv.h>
158 #include <openssl/bn.h>
159 #include <openssl/rsa.h>
160 #include <openssl/pkcs12.h>
161
162 /* Ugly workaround for Openssl 1.0 bug per:
163 * http://rt.openssl.org/Ticket/Display.html?user=guest&pass=guest&id=2123
164 */
165 #if (OPENSSL_VERSION_NUMBER == 0x10000003L)
166 #define i2d_ASN1_SET i2d_ASN1_SET_buggy
167 #define d2i_ASN1_SET d2i_ASN1_SET_buggy
168 #define ASN1_seq_unpack ASN1_seq_unpack_buggy
169 #define ASN1_seq_pack ASN1_seq_pack_buggy
170 #include <openssl/asn1.h>
171 #undef i2d_ASN1_SET
172 #undef d2i_ASN1_SET
173 #undef ASN1_seq_unpack
174 #undef ASN1_seq_pack
175
176 #ifdef __cplusplus
177 extern "C" {
178 #endif
179 int i2d_ASN1_SET(void *a, unsigned char **pp,
180 i2d_of_void *i2d, int ex_tag, int ex_class,
181 int is_set);
182 void *d2i_ASN1_SET(void *a, const unsigned char **pp,
183 long length, d2i_of_void *d2i,
184 void (*free_func)(void* p), int ex_tag,
185 int ex_class);
186 void *ASN1_seq_unpack(const unsigned char *buf, int len,
187 d2i_of_void *d2i, void (*free_func)(void* dummy));
188 unsigned char *ASN1_seq_pack(void *safes, i2d_of_void *i2d,
189 unsigned char **buf, int *len);
190 #ifdef __cplusplus
191 }
192 #endif
193
194 #endif // OpenSSL v1.0
195 // Work with OpenSSL 1.1.0 and later
196 #if OPENSSL_VERSION_NUMBER >= 0x10100000L && !defined(LIBRESSL_VERSION_NUMBER)
197 # define M_PKCS12_bag_type PKCS12_bag_type
198 # define M_PKCS12_cert_bag_type PKCS12_cert_bag_type
199 # define M_PKCS12_crl_bag_type PKCS12_cert_bag_type
200 # define M_PKCS12_certbag2x509 PKCS12_SAFEBAG_get1_cert
201 # define M_PKCS12_decrypt_skey PKCS12_decrypt_skey
202 # define M_PKCS12_unpack_authsafes PKCS12_unpack_authsafes
203 # define M_PKCS12_pack_authsafes PKCS12_pack_authsafes
204 # define PKCS12_get_attr PKCS12_SAFEBAG_get0_attr
205 # define PKCS12_bag_type PKCS12_SAFEBAG_get_nid
206 # define PKCS12_cert_bag_type PKCS12_SAFEBAG_get_bag_nid
207 # define PKCS12_x5092certbag PKCS12_SAFEBAG_create_cert
208 # define PKCS12_x509crl2certbag PKCS12_SAFEBAG_create_crl
209 # define X509_STORE_CTX_trusted_stack X509_STORE_CTX_set0_trusted_stack
210 # define X509_get_notAfter X509_get0_notAfter
211 # define X509_get_notBefore X509_get0_notBefore
212 # define PKCS12_MAKE_SHKEYBAG PKCS12_SAFEBAG_create_pkcs8_encrypt
213 # define X509_V_FLAG_CB_ISSUER_CHECK 0x0
214 #else
215 # define ASN1_STRING_get0_data ASN1_STRING_data
216 #endif
217 #include <map>
218 #include <vector>
219 #include <set>
220 #include <string>
221 #include <fstream>
222 #include <iostream>
223
224 #include "tqsllib.h"
225 #include "tqslerrno.h"
226 #include "xml.h"
227
228 #include "winstrdefs.h"
229
230 #ifdef _MSC_VER //is a visual studio compiler
231 #include "windirent.h"
232 #endif
233
234 #define tqsl_malloc malloc
235 #define tqsl_realloc realloc
236 #define tqsl_calloc calloc
237 #define tqsl_free free
238
239 #define TQSL_OBJ_TO_API(x) (reinterpret_cast<void *>((x)))
240 #define TQSL_API_TO_OBJ(x, type) ((type)(x))
241 #define TQSL_API_TO_CERT(x) TQSL_API_TO_OBJ((x), tqsl_cert *)
242
243 #include "openssl_cert.h"
244
245 using std::vector;
246 using std::map;
247 using std::set;
248 using std::string;
249 using std::ofstream;
250 using std::ios;
251 using std::endl;
252 using std::exception;
253 using tqsllib::XMLElement;
254 using tqsllib::XMLElementList;
255
256 #ifdef _WIN32
257 #define TQSL_OPEN_READ L"rb"
258 #define TQSL_OPEN_WRITE L"wb"
259 #define TQSL_OPEN_APPEND L"ab"
260 #else
261 #define TQSL_OPEN_READ "r"
262 #define TQSL_OPEN_WRITE "w"
263 #define TQSL_OPEN_APPEND "a"
264 #endif
265
266 #if (OPENSSL_VERSION_NUMBER & 0xfffff000) >= 0x10000000L
267 #define uni2asc OPENSSL_uni2asc
268 #define asc2uni OPENSSL_asc2uni
269 #endif
270
271 static char *tqsl_trim(char *buf);
272 static int tqsl_check_parm(const char *p, const char *parmName);
273 static TQSL_CERT_REQ *tqsl_copy_cert_req(TQSL_CERT_REQ *userreq);
274 static TQSL_CERT_REQ *tqsl_free_cert_req(TQSL_CERT_REQ *req, int seterr);
275 static char *tqsl_make_key_path(const char *callsign, char *path, int size);
276 static int tqsl_make_key_list(vector< map<string, string> > & keys);
277 static int tqsl_find_matching_key(X509 *cert, EVP_PKEY **keyp, TQSL_CERT_REQ **crq, const char *password, int (*cb)(char *, int, void *), void *);
278 static char *tqsl_make_cert_path(const char *filename, char *path, int size);
279 static char *tqsl_make_backup_path(const char *filename, char *path, int size);
280 static int tqsl_get_cert_ext(X509 *cert, const char *ext, unsigned char *userbuf, int *buflen, int *crit);
281 CLIENT_STATIC int tqsl_get_asn1_date(const ASN1_TIME *tm, tQSL_Date *date);
282 static char *tqsl_sign_base64_data(tQSL_Cert cert, char *b64data);
283 static int fixed_password_callback(char *buf, int bufsiz, int verify, void *userdata);
284 static int prompted_password_callback(char *buf, int bufsiz, int verify, void *userfunc);
285 static int tqsl_check_crq_field(tQSL_Cert cert, char *buf, int bufsiz);
286 static bool safe_strncpy(char *dest, const char *src, int size);
287 static int tqsl_ssl_error_is_nofile();
288 static int tqsl_unlock_key(const char *pem, EVP_PKEY **keyp, const char *password, int (*cb)(char *, int, void *), void *);
289 static int tqsl_replace_key(const char *callsign, const char *path, map<string, string>& newfields, int (*cb)(int, const char *, void *), void *);
290 static int tqsl_self_signed_is_ok(int ok, X509_STORE_CTX *ctx);
291 static int tqsl_expired_is_ok(int ok, X509_STORE_CTX *ctx);
292 static int tqsl_clear_deleted(const char *callsign, const char *path, EVP_PKEY *cert_key);
293 static int tqsl_key_exists(const char *callsign, EVP_PKEY *cert_key);
294 static int tqsl_open_key_file(const char *path);
295
296 extern const char* tqsl_openssl_error(void);
297
298 /* Private data structures */
299
300 typedef struct {
301 long id;
302 X509 *cert;
303 EVP_PKEY *key;
304 TQSL_CERT_REQ *crq;
305 char *pubkey;
306 char *privkey;
307 unsigned char keyonly;
308 } tqsl_cert;
309
310 typedef struct {
311 long id;
312 X509 *cert;
313 } tqsl_crq;
314
315 static tqsl_cert * tqsl_cert_new();
316 static void tqsl_cert_free(tqsl_cert *p);
317 static int tqsl_cert_check(tqsl_cert *p, bool needcert = true);
318
319 struct tqsl_loadcert_handler {
320 int type;
321 int (*func)(const char *pem, X509 *x, int(*cb)(int type, const char *, void *), void *);
322 };
323
324 static int tqsl_handle_root_cert(const char *, X509 *, int (*cb)(int, const char *, void *), void *);
325 static int tqsl_handle_ca_cert(const char *, X509 *, int (*cb)(int, const char *, void *), void *);
326 static int tqsl_handle_user_cert(const char *, X509 *, int (*cb)(int, const char *, void *), void *);
327
328 static struct tqsl_loadcert_handler tqsl_loadcert_handlers[] = {
329 { TQSL_CERT_CB_ROOT, &tqsl_handle_root_cert },
330 { TQSL_CERT_CB_CA, &tqsl_handle_ca_cert },
331 { TQSL_CERT_CB_USER, &tqsl_handle_user_cert }
332 };
333
334 static const char *notypes[] = { "" };
335 /*
336 static tqsl_adifFieldDefinitions tqsl_cert_file_fields[] = {
337 { "TQSL_CERT", "", TQSL_ADIF_RANGE_TYPE_NONE, 0, 0, 0, NULL, NULL },
338 { "TQSL_CERT_USER", "", TQSL_ADIF_RANGE_TYPE_NONE, 2000, 0, 0, NULL, &tqsl_load_user_cert },
339 { "TQSL_CERT_CA", "", TQSL_ADIF_RANGE_TYPE_NONE, 2000, 0, 0, NULL, &tqsl_load_ca_cert },
340 { "TQSL_CERT_ROOT", "", TQSL_ADIF_RANGE_TYPE_NONE, 2000, 0, 0, NULL, &tqsl_load_root_cert },
341 };
342 */
343
344 static unsigned char tqsl_static_buf[2001];
345
346 static char ImportCall[256];
347
348 static unsigned char *
tqsl_static_alloc(size_t size)349 tqsl_static_alloc(size_t size) {
350 if (size > sizeof tqsl_static_buf)
351 return NULL;
352 strncpy(reinterpret_cast<char *>(tqsl_static_buf), "<EMPTY>", sizeof tqsl_static_buf);
353 return tqsl_static_buf;
354 }
355
356 namespace tqsllib {
357
358 int
tqsl_import_cert(const char * data,certtype type,int (* cb)(int,const char *,void *),void * userdata)359 tqsl_import_cert(const char *data, certtype type, int(*cb)(int, const char *, void *), void *userdata) {
360 BIO *bio;
361 X509 *cert;
362 int stat;
363 struct tqsl_loadcert_handler *handler = &(tqsl_loadcert_handlers[type]);
364
365 /* This is a certificate, supposedly. Let's make sure */
366
367 tqslTrace("tqsl_import_cert", NULL);
368 bio = BIO_new_mem_buf(reinterpret_cast<void *>(const_cast<char *>(data)), strlen(data));
369 if (bio == NULL) {
370 tqslTrace("tqsl_import_cert", "BIO mem buf error %s", tqsl_openssl_error());
371 tQSL_Error = TQSL_OPENSSL_ERROR;
372 return 1;
373 }
374 cert = PEM_read_bio_X509(bio, NULL, NULL, NULL);
375 BIO_free(bio);
376 if (cert == NULL) {
377 tqslTrace("tqsl_import_cert", "BIO read error, err=%s", tqsl_openssl_error());
378 tQSL_Error = TQSL_OPENSSL_ERROR;
379 return 1;
380 }
381 /* It's a certificate. Let's try to add it. Any errors will be
382 * reported via the callback (if any) but will not be fatal unless
383 * the callback says so.
384 */
385 ImportCall[0] = '\0';
386 tQSL_ImportSerial = 0;
387 stat = (*(handler->func))(data, cert, cb, userdata);
388 X509_free(cert);
389 if (stat) {
390 if (tQSL_Error == TQSL_CERT_ERROR) {
391 return 1;
392 }
393 if (cb != NULL) {
394 stat = (*cb)(handler->type | TQSL_CERT_CB_RESULT | TQSL_CERT_CB_ERROR, tqsl_getErrorString_v(tQSL_Error), userdata);
395 if (stat) {
396 tqslTrace("tqsl_import_cert", "import error %d", tQSL_Error);
397 return 1;
398 } else {
399 tqslTrace("tqsl_import_cert", "import error. Handler suppressed.");
400 }
401 } else {
402 /* No callback -- any errors are fatal */
403 tqslTrace("tqsl_import_cert", "import error %d", tQSL_Error);
404 return 1;
405 }
406 return stat;
407 }
408 strncpy(tQSL_ImportCall, ImportCall, sizeof tQSL_ImportCall);
409 return 0;
410 }
411
412 int
tqsl_get_pem_serial(const char * pem,long * serial)413 tqsl_get_pem_serial(const char *pem, long *serial) {
414 BIO *bio;
415 X509 *cert;
416
417 tqslTrace("tqsl_get_pem_serial", NULL);
418 if (tqsl_init())
419 return 1;
420 if (pem == NULL || serial == NULL) {
421 tqslTrace("tqsl_get_pem_serial", "arg error pem=0x%lx, serial=0x%lx", pem, serial);
422 tQSL_Error = TQSL_ARGUMENT_ERROR;
423 return 1;
424 }
425 bio = BIO_new_mem_buf(reinterpret_cast<void *>(const_cast<char *>(pem)), strlen(pem));
426 if (bio == NULL) {
427 tqslTrace("tqsl_get_pem_serial", "mem buf error %s", tqsl_openssl_error());
428 tQSL_Error = TQSL_OPENSSL_ERROR;
429 return 1;
430 }
431 cert = PEM_read_bio_X509(bio, NULL, NULL, NULL);
432 BIO_free(bio);
433 if (cert == NULL) {
434 tqslTrace("tqsl_get_pem_serial", "cert read error %s", tqsl_openssl_error());
435 tQSL_Error = TQSL_OPENSSL_ERROR;
436 return 1;
437 }
438 *serial = ASN1_INTEGER_get(X509_get_serialNumber(cert));
439 return 0;
440 }
441
442 } // namespace tqsllib
443
444 /********** PUBLIC API FUNCTIONS ***********/
445
446 DLLEXPORT int CALLCONVENTION
tqsl_createCertRequest(const char * filename,TQSL_CERT_REQ * userreq,int (* pwcb)(char * pwbuf,int pwsize,void *),void * userdata)447 tqsl_createCertRequest(const char *filename, TQSL_CERT_REQ *userreq,
448 int (*pwcb)(char *pwbuf, int pwsize, void *), void *userdata) {
449 TQSL_CERT_REQ *req = NULL;
450 EVP_PKEY *key = NULL;
451 X509_REQ *xr = NULL;
452 X509_NAME *subj = NULL;
453 int nid, len;
454 int rval = 1;
455 FILE *out = NULL;
456 BIO *bio = NULL;
457 const EVP_MD *digest = NULL;
458 char buf[200];
459 char path[256];
460 char *cp;
461 const EVP_CIPHER *cipher = NULL;
462 char *password;
463 const char *type;
464
465 tqslTrace("tqsl_createCertRequest", NULL);
466 if (tqsl_init())
467 return 1;
468 if (filename == NULL || userreq == NULL) {
469 tqslTrace("tqsl_createCertRequest", "arg error filename=0x%lx, userreq=0x%lx", filename, userreq);
470 tQSL_Error = TQSL_ARGUMENT_ERROR;
471 return 1;
472 }
473 if (userreq->signer != NULL && (!tqsl_cert_check(TQSL_API_TO_CERT(userreq->signer))
474 || TQSL_API_TO_CERT(userreq->signer)->key == NULL)) {
475 tqslTrace("tqsl_createCertRequest", "arg error signer/key");
476 tQSL_Error = TQSL_ARGUMENT_ERROR;
477 return 1;
478 }
479 if ((req = tqsl_copy_cert_req(userreq)) == NULL) {
480 tqslTrace("tqsl_createCertRequest", "Error copying %d", tQSL_Error);
481 goto end;
482 }
483
484 /* Check parameters for validity */
485
486 tqsl_trim(req->providerName);
487 tqsl_trim(req->providerUnit);
488 tqsl_trim(req->name);
489 if (tqsl_check_parm(req->name, "Name")) {
490 tqslTrace("tqsl_createCertRequest", "check_parm Name");
491 goto end;
492 }
493 tqsl_trim(req->callSign);
494 if (tqsl_check_parm(req->callSign, "Call Sign")) {
495 tqslTrace("tqsl_createCertRequest", "check_parm Call Sign");
496 goto end;
497 }
498 tqsl_trim(req->address1);
499 if (tqsl_check_parm(req->address1, "Address")) {
500 tqslTrace("tqsl_createCertRequest", "check_parm Address1");
501 goto end;
502 }
503 tqsl_trim(req->address2);
504 tqsl_trim(req->city);
505 if (tqsl_check_parm(req->city, "City")) {
506 tqslTrace("tqsl_createCertRequest", "check_parm City");
507 goto end;
508 }
509 tqsl_trim(req->state);
510 tqsl_trim(req->country);
511 if (tqsl_check_parm(req->country, "Country")) {
512 tqslTrace("tqsl_createCertRequest", "check_parm Country");
513 goto end;
514 }
515 tqsl_trim(req->postalCode);
516 tqsl_trim(req->emailAddress);
517 if (tqsl_check_parm(req->emailAddress, "Email address")) {
518 tqslTrace("tqsl_createCertRequest", "check_parm email");
519 goto end;
520 }
521 if ((cp = strchr(req->emailAddress, '@')) == NULL || strchr(cp, '.') == NULL) {
522 strncpy(tQSL_CustomError, "Invalid email address", sizeof tQSL_CustomError);
523 tQSL_Error = TQSL_CUSTOM_ERROR;
524 tqslTrace("tqsl_createCertRequest", "check_parm email: %s %s", req->emailAddress, tQSL_CustomError);
525 goto end;
526 }
527 if (!tqsl_isDateValid(&(req->qsoNotBefore))) {
528 strncpy(tQSL_CustomError, "Invalid date (qsoNotBefore)", sizeof tQSL_CustomError);
529 tqslTrace("tqsl_createCertRequest", "check_parm not before: %s %s", req->qsoNotBefore, tQSL_CustomError);
530 tQSL_Error = TQSL_CUSTOM_ERROR;
531 goto end;
532 }
533 if (!tqsl_isDateNull(&(req->qsoNotAfter))) {
534 if (!tqsl_isDateValid(&(req->qsoNotAfter))) {
535 strncpy(tQSL_CustomError, "Invalid date (qsoNotAfter)", sizeof tQSL_CustomError);
536 tqslTrace("tqsl_createCertRequest", "check_parm not after: %s %s", req->qsoNotAfter, tQSL_CustomError);
537 tQSL_Error = TQSL_CUSTOM_ERROR;
538 goto end;
539 }
540 if (tqsl_compareDates(&(req->qsoNotAfter), &(req->qsoNotBefore)) < 0) {
541 strncpy(tQSL_CustomError, "qsoNotAfter date is earlier than qsoNotBefore", sizeof tQSL_CustomError);
542 tqslTrace("tqsl_createCertRequest", "check_parm not after: %s %s", req->qsoNotAfter, tQSL_CustomError);
543 tQSL_Error = TQSL_CUSTOM_ERROR;
544 goto end;
545 }
546 }
547
548 /* Try opening the output stream */
549
550 #ifdef _WIN32
551 wchar_t* wfilename = utf8_to_wchar(filename);
552 if ((out = _wfopen(wfilename, TQSL_OPEN_WRITE)) == NULL) {
553 free_wchar(wfilename);
554 #else
555 if ((out = fopen(filename, TQSL_OPEN_WRITE)) == NULL) {
556 #endif
557 strncpy(tQSL_ErrorFile, filename, sizeof tQSL_ErrorFile);
558 tqslTrace("tqsl_createCertRequest", "Open file - system error %s", strerror(errno));
559 tQSL_Error = TQSL_SYSTEM_ERROR;
560 tQSL_Errno = errno;
561 goto end;
562 }
563 #ifdef _WIN32
564 free_wchar(wfilename);
565 #endif
566 if (fputs("\ntQSL certificate request\n\n", out) == EOF) {
567 strncpy(tQSL_ErrorFile, filename, sizeof tQSL_ErrorFile);
568 tqslTrace("tqsl_createCertRequest", "Write request file - system error %s", strerror(errno));
569 tQSL_Error = TQSL_SYSTEM_ERROR;
570 tQSL_Errno = errno;
571 goto end;
572 }
573 tqsl_write_adif_field(out, "eoh", 0, NULL, 0);
574 type = (req->signer != NULL) ? (req->renew ? "TQSL_CRQ_RENEWAL" : "TQSL_CRQ_ADDITIONAL") : "TQSL_CRQ_NEW";
575 int libmaj, libmin, configmaj, configmin;
576 tqsl_getVersion(&libmaj, &libmin);
577 tqsl_getConfigVersion(&configmaj, &configmin);
578 snprintf(buf, sizeof buf, "Lib: V%d.%d, Config: %d, %d", libmaj, libmin, configmaj, configmin);
579 tqsl_write_adif_field(out, "TQSL_IDENT", 0, (unsigned char *)buf, -1);
580 tqsl_write_adif_field(out, type, 0, NULL, 0);
581 tqsl_write_adif_field(out, "TQSL_CRQ_PROVIDER", 0, (unsigned char *)req->providerName, -1);
582 tqsl_write_adif_field(out, "TQSL_CRQ_PROVIDER_UNIT", 0, (unsigned char *)req->providerUnit, -1);
583 tqsl_write_adif_field(out, "TQSL_CRQ_EMAIL", 0, (unsigned char *)req->emailAddress, -1);
584 tqsl_write_adif_field(out, "TQSL_CRQ_ADDRESS1", 0, (unsigned char *)req->address1, -1);
585 tqsl_write_adif_field(out, "TQSL_CRQ_ADDRESS2", 0, (unsigned char *)req->address2, -1);
586 tqsl_write_adif_field(out, "TQSL_CRQ_CITY", 0, (unsigned char *)req->city, -1);
587 tqsl_write_adif_field(out, "TQSL_CRQ_STATE", 0, (unsigned char *)req->state, -1);
588 tqsl_write_adif_field(out, "TQSL_CRQ_POSTAL", 0, (unsigned char *)req->postalCode, -1);
589 tqsl_write_adif_field(out, "TQSL_CRQ_COUNTRY", 0, (unsigned char *)req->country, -1);
590 snprintf(buf, sizeof buf, "%d", req->dxccEntity);
591 tqsl_write_adif_field(out, "TQSL_CRQ_DXCC_ENTITY", 0, (unsigned char *)buf, -1);
592 tqsl_convertDateToText(&(req->qsoNotBefore), buf, sizeof buf);
593 tqsl_write_adif_field(out, "TQSL_CRQ_QSO_NOT_BEFORE", 0, (unsigned char *)buf, -1);
594 if (!tqsl_isDateNull(&(req->qsoNotAfter))) {
595 tqsl_convertDateToText(&(req->qsoNotAfter), buf, sizeof buf);
596 tqsl_write_adif_field(out, "TQSL_CRQ_QSO_NOT_AFTER", 0, (unsigned char *)buf, -1);
597 }
598
599 /* Generate a new key pair */
600
601 if ((key = tqsl_new_rsa_key(1024)) == NULL) {
602 tqslTrace("tqsl_createCertRequest", "key create error %d", tQSL_Error);
603 goto end;
604 }
605
606 /* Make the X.509 certificate request */
607
608 if ((xr = X509_REQ_new()) == NULL) {
609 tqslTrace("tqsl_createCertRequest", "req create error %s", tqsl_openssl_error());
610 goto err;
611 }
612 if (!X509_REQ_set_version(xr, 0L)) {
613 tqslTrace("tqsl_createCertRequest", "version set error %s", tqsl_openssl_error());
614 goto err;
615 }
616 subj = X509_REQ_get_subject_name(xr);
617 nid = OBJ_txt2nid("AROcallsign");
618 if (nid != NID_undef)
619 X509_NAME_add_entry_by_NID(subj, nid, MBSTRING_ASC, (unsigned char *)req->callSign, -1, -1, 0);
620 nid = OBJ_txt2nid("commonName");
621 if (nid != NID_undef)
622 X509_NAME_add_entry_by_NID(subj, nid, MBSTRING_ASC, (unsigned char *)req->name, -1, -1, 0);
623 nid = OBJ_txt2nid("emailAddress");
624 if (nid != NID_undef)
625 X509_NAME_add_entry_by_NID(subj, nid, MBSTRING_ASC, (unsigned char *)req->emailAddress, -1, -1, 0);
626 X509_REQ_set_pubkey(xr, key);
627 if ((digest = EVP_sha256()) == NULL) {
628 tqslTrace("tqsl_createCertRequest", "evp_sha256 error %s", tqsl_openssl_error());
629 goto err;
630 }
631 if (!X509_REQ_sign(xr, key, digest)) {
632 tqslTrace("tqsl_createCertRequest", "req_sign error %s", tqsl_openssl_error());
633 goto err;
634 }
635 if ((bio = BIO_new(BIO_s_mem())) == NULL) {
636 tqslTrace("tqsl_createCertRequest", "bio_new error %s", tqsl_openssl_error());
637 goto err;
638 }
639 if (!PEM_write_bio_X509_REQ(bio, xr)) {
640 tqslTrace("tqsl_createCertRequest", "write_bio error %s", tqsl_openssl_error());
641 goto err;
642 }
643 len = static_cast<int>(BIO_get_mem_data(bio, &cp));
644 tqsl_write_adif_field(out, "TQSL_CRQ_REQUEST", 0, (unsigned char *)cp, len);
645
646 if (req->signer != NULL) {
647 char *b64;
648 char ibuf[256];
649
650 if ((b64 = tqsl_sign_base64_data(req->signer, cp)) == NULL) {
651 fclose(out);
652 tqslTrace("tqsl_createCertRequest", "tqsl_sign_base64 error %s", tqsl_openssl_error());
653 goto end;
654 }
655 tqsl_write_adif_field(out, "TQSL_CRQ_SIGNATURE", 0, (unsigned char *)b64, -1);
656 tqsl_getCertificateIssuer(req->signer, ibuf, sizeof ibuf);
657 tqsl_write_adif_field(out, "TQSL_CRQ_SIGNATURE_CERT_ISSUER", 0, (unsigned char *)ibuf, -1);
658 snprintf(ibuf, sizeof ibuf, "%ld", ASN1_INTEGER_get(X509_get_serialNumber(TQSL_API_TO_CERT(req->signer)->cert)));
659 tqsl_write_adif_field(out, "TQSL_CRQ_SIGNATURE_CERT_SERIAL", 0, (unsigned char *)ibuf, -1);
660 }
661
662 BIO_free(bio);
663 bio = NULL;
664 tqsl_write_adif_field(out, "eor", 0, NULL, 0);
665 if (fclose(out) == EOF) {
666 strncpy(tQSL_ErrorFile, filename, sizeof tQSL_ErrorFile);
667 tQSL_Error = TQSL_SYSTEM_ERROR;
668 tQSL_Errno = errno;
669 tqslTrace("tqsl_createCertRequest", "write error %d", errno);
670 goto end;
671 }
672 out = NULL;
673
674 /* Write the key to the key store */
675
676 if (!tqsl_make_key_path(req->callSign, path, sizeof path)) {
677 tqslTrace("tqsl_createCertRequest", "make_key_path error %d", errno);
678 goto end;
679 }
680 #ifdef _WIN32
681 wchar_t* wpath = utf8_to_wchar(path);
682 if ((out = _wfopen(wpath, TQSL_OPEN_APPEND)) == NULL) {
683 free_wchar(wpath);
684 #else
685 if ((out = fopen(path, TQSL_OPEN_APPEND)) == NULL) {
686 #endif
687 strncpy(tQSL_ErrorFile, path, sizeof tQSL_ErrorFile);
688 tQSL_Error = TQSL_SYSTEM_ERROR;
689 tQSL_Errno = errno;
690 tqslTrace("tqsl_createCertRequest", "opening file error %s", strerror(errno));
691 goto end;
692 }
693 #ifdef _WIN32
694 free_wchar(wpath);
695 #endif
696 tqsl_write_adif_field(out, "TQSL_CRQ_PROVIDER", 0, (unsigned char *)req->providerName, -1);
697 tqsl_write_adif_field(out, "TQSL_CRQ_PROVIDER_UNIT", 0, (unsigned char *)req->providerUnit, -1);
698 tqsl_write_adif_field(out, "TQSL_CRQ_EMAIL", 0, (unsigned char *)req->emailAddress, -1);
699 tqsl_write_adif_field(out, "TQSL_CRQ_ADDRESS1", 0, (unsigned char *)req->address1, -1);
700 tqsl_write_adif_field(out, "TQSL_CRQ_ADDRESS2", 0, (unsigned char *)req->address2, -1);
701 tqsl_write_adif_field(out, "TQSL_CRQ_CITY", 0, (unsigned char *)req->city, -1);
702 tqsl_write_adif_field(out, "TQSL_CRQ_STATE", 0, (unsigned char *)req->state, -1);
703 tqsl_write_adif_field(out, "TQSL_CRQ_POSTAL", 0, (unsigned char *)req->postalCode, -1);
704 tqsl_write_adif_field(out, "TQSL_CRQ_COUNTRY", 0, (unsigned char *)req->country, -1);
705 tqsl_write_adif_field(out, "CALLSIGN", 0, (unsigned char *)req->callSign, -1);
706 snprintf(buf, sizeof buf, "%d", req->dxccEntity);
707 tqsl_write_adif_field(out, "TQSL_CRQ_DXCC_ENTITY", 0, (unsigned char *)buf, -1);
708 tqsl_convertDateToText(&(req->qsoNotBefore), buf, sizeof buf);
709 tqsl_write_adif_field(out, "TQSL_CRQ_QSO_NOT_BEFORE", 0, (unsigned char *)buf, -1);
710 if (!tqsl_isDateNull(&(req->qsoNotAfter))) {
711 tqsl_convertDateToText(&(req->qsoNotAfter), buf, sizeof buf);
712 tqsl_write_adif_field(out, "TQSL_CRQ_QSO_NOT_AFTER", 0, (unsigned char *)buf, -1);
713 }
714 if ((bio = BIO_new(BIO_s_mem())) == NULL) {
715 tqslTrace("tqsl_createCertRequest", "bio_new error %s", tqsl_openssl_error());
716 goto err;
717 }
718 password = const_cast<char *>(req->password);
719 if (password == NULL && pwcb != NULL) {
720 if ((*pwcb)(buf, TQSL_MAX_PW_LENGTH, userdata)) {
721 tqslTrace("tqsl_createCertRequest", "password abort");
722 tQSL_Error = TQSL_OPERATOR_ABORT;
723 goto end;
724 }
725 password = buf;
726 }
727 if (password != NULL && *password != '\0') {
728 if ((cipher = EVP_des_ede3_cbc()) == NULL) {
729 tqslTrace("tqsl_createCertRequest", "password error");
730 goto err;
731 }
732 len = strlen(password);
733 } else {
734 password = NULL;
735 len = 0;
736 }
737 if (!PEM_write_bio_PrivateKey(bio, key, cipher, (unsigned char *)password, len, NULL, NULL)) {
738 tqslTrace("tqsl_createCertRequest", "write priv key error %s", tqsl_openssl_error());
739 goto err;
740 }
741 len = static_cast<int>(BIO_get_mem_data(bio, &cp));
742 tqsl_write_adif_field(out, "PRIVATE_KEY", 0, (unsigned char *)cp, len);
743 BIO_free(bio);
744 if ((bio = BIO_new(BIO_s_mem())) == NULL) {
745 tqslTrace("tqsl_createCertRequest", "bio_new error %s", tqsl_openssl_error());
746 goto err;
747 }
748 if (!PEM_write_bio_PUBKEY(bio, key)) {
749 tqslTrace("tqsl_createCertRequest", "write pubkey %s", tqsl_openssl_error());
750 goto err;
751 }
752 len = static_cast<int>(BIO_get_mem_data(bio, &cp));
753 tqsl_write_adif_field(out, "PUBLIC_KEY", 0, (unsigned char *)cp, len);
754 BIO_free(bio);
755 bio = NULL;
756 tqsl_write_adif_field(out, "eor", 0, NULL, 0);
757 if (fclose(out) == EOF) {
758 tQSL_Error = TQSL_SYSTEM_ERROR;
759 tQSL_Errno = errno;
760 tqslTrace("tqsl_createCertRequest", "write file error %s", strerror(tQSL_Errno));
761 goto end;
762 }
763 out = NULL;
764
765 rval = 0;
766 goto end;
767 err:
768 tQSL_Error = TQSL_OPENSSL_ERROR;
769 end:
770 if (bio != NULL)
771 BIO_free(bio);
772 if (out != NULL)
773 fclose(out);
774 if (xr != NULL)
775 X509_REQ_free(xr);
776 if (key != NULL)
777 EVP_PKEY_free(key);
778 if (req != NULL)
779 tqsl_free_cert_req(req, 0);
780 return rval;
781 }
782
783 DLLEXPORT int CALLCONVENTION
784 tqsl_getSelectedCertificate(tQSL_Cert *cert, const tQSL_Cert **certlist,
785 int idx) {
786 tqslTrace("tqsl_getSelectedCertificate", NULL);
787 if (tqsl_init())
788 return 1;
789 if (certlist == NULL || cert == NULL || idx < 0) {
790 tqslTrace("tqsl_getSelectedCertificate", "arg error certlist=0x%lx, cert=0x%lx, idx=%d", certlist, cert, idx);
791 tQSL_Error = TQSL_ARGUMENT_ERROR;
792 return 1;
793 }
794 *cert = (*certlist)[idx];
795 return 0;
796 }
797
798 DLLEXPORT int CALLCONVENTION
799 tqsl_isCertificateExpired(tQSL_Cert cert, int *status) {
800 tqslTrace("tqsl_isCertificateExpired", NULL);
801 if (tqsl_init())
802 return 1;
803 if (cert == NULL || status == NULL || !tqsl_cert_check(TQSL_API_TO_CERT(cert), false)) {
804 tqslTrace("tqsl_isCertificateExpired", "arg error cert=0x%lx status=0x%lx", cert, status);
805 tQSL_Error = TQSL_ARGUMENT_ERROR;
806 if (status) *status = false;
807 return 1;
808 }
809
810 int keyonly;
811 if (tqsl_getCertificateKeyOnly(cert, &keyonly) == 0 && keyonly) {
812 *status = false;
813 return 0;
814 }
815
816 long serial = 0;
817 tqsl_getCertificateSerial(cert, &serial);
818 if (tqsl_getCertificateStatus(serial) == TQSL_CERT_STATUS_EXP) {
819 *status = true;
820 return 0;
821 }
822 *status = false;
823 /* Check for expired */
824 time_t t = time(0);
825 struct tm *tm = gmtime(&t);
826 tQSL_Date d;
827 d.year = tm->tm_year + 1900;
828 d.month = tm->tm_mon + 1;
829 d.day = tm->tm_mday;
830 const ASN1_TIME *ctm;
831 if ((ctm = X509_get_notAfter(TQSL_API_TO_CERT(cert)->cert)) == NULL) {
832 *status = true;
833 return 0;
834 } else {
835 tQSL_Date cert_na;
836 tqsl_get_asn1_date(ctm, &cert_na);
837 if (tqsl_compareDates(&cert_na, &d) < 0) {
838 *status = true;
839 return 0;
840 }
841 }
842 return 0;
843 }
844
845 static TQSL_X509_STACK *xcerts = NULL;
846 DLLEXPORT int CALLCONVENTION
847 tqsl_isCertificateSuperceded(tQSL_Cert cert, int *status) {
848 char path[256];
849 int i;
850 X509 *x = NULL;
851 char *cp;
852 vector< map<string, string> > keylist;
853 vector< map<string, string> >::iterator it;
854 set<string> superceded_certs;
855 int len;
856 bool superceded = false;
857 char buf[256];
858
859 tqslTrace("tqsl_isCertificateSuperceded", NULL);
860 if (tqsl_init())
861 return 1;
862 if (cert == NULL || status == NULL || !tqsl_cert_check(TQSL_API_TO_CERT(cert), false)) {
863 tqslTrace("tqsl_isCertificateSuperceded", "arg error cert=0x%lx, status=0x%lx", cert, status);
864 tQSL_Error = TQSL_ARGUMENT_ERROR;
865 return 1;
866 }
867
868 *status = false;
869 int keyonly;
870 if (tqsl_getCertificateKeyOnly(cert, &keyonly) == 0 && keyonly) {
871 return 0;
872 }
873
874 long serial = 0;
875 tqsl_getCertificateSerial(cert, &serial);
876 if (tqsl_getCertificateStatus(serial) == TQSL_CERT_STATUS_SUP) {
877 *status = true;
878 tqslTrace("tqsl_isCertificateSuperceded", "returning true");
879 return 0;
880 }
881 /* Get the certs from the cert store */
882 tqsl_make_cert_path("user", path, sizeof path);
883 if (xcerts == NULL)
884 xcerts = tqsl_ssl_load_certs_from_file(path);
885 if (xcerts == NULL) {
886 if (tQSL_Error == TQSL_OPENSSL_ERROR) {
887 tqslTrace("tqsl_isCertificateSuperceded", "openssl error loading certs %d", tQSL_Error);
888 return 1;
889 }
890 }
891 /* Make a list of superceded certs */
892 for (i = 0; i < sk_X509_num(xcerts); i++) {
893 x = sk_X509_value(xcerts, i);
894 len = sizeof buf-1;
895 if (!tqsl_get_cert_ext(x, "supercededCertificate", (unsigned char *)buf, &len, NULL)) {
896 buf[len] = 0;
897 string sup = buf;
898 superceded_certs.insert(sup);
899 /* Fix - the extension as inserted by ARRL
900 * reads ".../Email=lotw@arrl.org", not
901 * the expected ".../emailAddress=".
902 * save both forms in case this gets
903 * changed at the LoTW site
904 */
905 size_t pos = sup.find("/Email");
906 if (pos != string::npos) {
907 sup.replace(pos, 6, "/emailAddress");
908 superceded_certs.insert(sup);
909 }
910 }
911 }
912
913 // "supercededCertificate" extension is <issuer>;<serial>
914 cp = X509_NAME_oneline(X509_get_issuer_name(TQSL_API_TO_CERT(cert)->cert), buf, sizeof(buf));
915 if (cp == NULL) {
916 superceded = false;
917 tqslTrace("tqsl_isCertificateSuperceded", "returning false");
918 } else {
919 string sup = buf;
920 sup += ";";
921 long serial = 0;
922 tqsl_getCertificateSerial(cert, &serial);
923 snprintf(buf, sizeof buf, "%ld", serial);
924 sup += buf;
925 if (superceded_certs.find(sup) != superceded_certs.end()) {
926 tqslTrace("tqsl_isCertificateSuperceded", "returning true");
927 superceded = true;
928 }
929 }
930 *status = superceded;
931 return 0;
932 }
933 DLLEXPORT int CALLCONVENTION
934 tqsl_selectCertificates(tQSL_Cert **certlist, int *ncerts,
935 const char *callsign, int dxcc, const tQSL_Date *date, const TQSL_PROVIDER *issuer, int flags) {
936 int withkeys = flags & TQSL_SELECT_CERT_WITHKEYS;
937 TQSL_X509_STACK *selcerts = NULL;
938 char path[256];
939 int i;
940 X509 *x;
941 int rval = 1;
942 tqsl_cert *cp;
943 TQSL_CERT_REQ *crq;
944 BIO *bio = NULL;
945 EVP_PKEY *pubkey = NULL;
946 EVP_PKEY *curkey = NULL;
947 vector< map<string, string> > keylist;
948 vector< map<string, string> >::iterator it;
949 bool keyerror = false;
950 int savedError;
951 int savedErrno;
952
953 tqslTrace("tqsl_selectCertificates", "callsign=%s, dxcc=%d, flags=%d", callsign ? callsign : "NULL", dxcc, flags);
954 if (tqsl_init())
955 return 1;
956 if (ncerts == NULL) {
957 tqslTrace("tqsl_selectCertificates", "arg error ncerts=0x%lx", ncerts);
958 tQSL_Error = TQSL_ARGUMENT_ERROR;
959 return 1;
960 }
961 *ncerts = 0;
962 if (certlist)
963 *certlist = NULL;
964
965 /* Convert the dates to tQSL_Date objects */
966 if (date && !tqsl_isDateNull(date) && !tqsl_isDateValid(date)) {
967 tqslTrace("tqsl_selectCertificates", "arg error - bad date");
968 tQSL_Error = TQSL_ARGUMENT_ERROR;
969 return 1;
970 }
971
972 /* Get the certs from the cert store */
973 tqsl_make_cert_path("user", path, sizeof path);
974 if (xcerts == NULL)
975 xcerts = tqsl_ssl_load_certs_from_file(path);
976 if (xcerts == NULL) {
977 if (tQSL_Error == TQSL_OPENSSL_ERROR) {
978 tqslTrace("tqsl_selectCertificates", "openssl error");
979 return 1;
980 } else if (tQSL_Error != TQSL_SYSTEM_ERROR || tQSL_Errno != ENOENT) { // No file
981 tqslTrace("tqsl_selectCertificates", "other error %d", tQSL_Error);
982 return 1;
983 }
984 } else {
985 selcerts = tqsl_filter_cert_list(xcerts, callsign, dxcc, date, issuer, flags);
986 }
987 // Get a list of keys and find any unmatched (no cert) ones
988 if (withkeys) {
989 if (tqsl_make_key_list(keylist)) {
990 keyerror = true; // Remember that an error occurred
991 savedError = tQSL_Error; // but allow the rest of the certs to load
992 savedErrno = tQSL_Errno;
993 tqslTrace("tqsl_selectCertificates", "make_key_list error %d %d", tQSL_Error, tQSL_Errno);
994 }
995 if (xcerts != NULL) {
996 for (i = 0; i < sk_X509_num(xcerts); i++) {
997 x = sk_X509_value(xcerts, i);
998 if ((pubkey = X509_get_pubkey(x)) == NULL) {
999 tqslTrace("tqsl_selectCertificates", "can't get pubkey");
1000 goto err;
1001 }
1002 for (it = keylist.begin(); it != keylist.end(); it++) {
1003 int match = 0;
1004 /* Compare the keys */
1005 string& keystr = (*it)["PUBLIC_KEY"];
1006 if ((bio = BIO_new_mem_buf(static_cast<void *>(const_cast<char *>(keystr.c_str())), keystr.length())) == NULL) {
1007 tqslTrace("tqsl_selectCertifcates", "bio_new error %s", tqsl_openssl_error());
1008 goto err;
1009 }
1010 if ((curkey = PEM_read_bio_PUBKEY(bio, NULL, NULL, NULL)) == NULL) {
1011 tqslTrace("tqsl_selectCertificates", "pem_read_bio err %s", tqsl_openssl_error());
1012 goto err;
1013 }
1014 BIO_free(bio);
1015 bio = NULL;
1016 if (EVP_PKEY_cmp(curkey, pubkey) == 1)
1017 match = 1;
1018 EVP_PKEY_free(curkey);
1019 curkey = NULL;
1020 if (match) {
1021 // Remove matched key from list
1022 keylist.erase(it);
1023 break;
1024 }
1025 }
1026 EVP_PKEY_free(pubkey);
1027 pubkey = NULL;
1028 }
1029 }
1030 // Filter keylist
1031 for (it = keylist.begin(); it != keylist.end(); ) {
1032 if ((*it)["TQSL_CRQ_PROVIDER"] == "")
1033 it = keylist.erase(it);
1034 else if (callsign && (*it)["CALLSIGN"] != callsign)
1035 it = keylist.erase(it);
1036 else if (dxcc && strtol((*it)["TQSL_CRQ_DXCC_ENTITY"].c_str(), NULL, 10) != dxcc)
1037 it = keylist.erase(it);
1038 else if (issuer && (*it)["TQSL_CRQ_PROVIDER"] != issuer->organizationName)
1039 it = keylist.erase(it);
1040 else if (issuer && (*it)["TQSL_CRQ_PROVIDER_UNIT"] != issuer->organizationalUnitName)
1041 it = keylist.erase(it);
1042 else
1043 it++;
1044 }
1045 }
1046
1047 //cerr << keylist.size() << " unmatched keys" << endl;
1048
1049 *ncerts = (selcerts ? sk_X509_num(selcerts) : 0) + keylist.size();
1050 tqslTrace("tqsl_selectCertificates", "ncerts=%d", *ncerts);
1051 if (certlist == NULL) // Only want certificate count
1052 goto end;
1053 *certlist = reinterpret_cast<tQSL_Cert *>(tqsl_calloc(*ncerts, sizeof(tQSL_Cert)));
1054 if (selcerts != NULL) {
1055 for (i = 0; i < sk_X509_num(selcerts); i++) {
1056 x = sk_X509_value(selcerts, i);
1057 if ((cp = tqsl_cert_new()) == NULL) {
1058 tqslTrace("tqsl_selectCertificates", "error making new cert - %s", tqsl_openssl_error());
1059 goto end;
1060 }
1061 cp->cert = X509_dup(x);
1062 (*certlist)[i] = TQSL_OBJ_TO_API(cp);
1063 }
1064 } else {
1065 i = 0;
1066 }
1067 for (it = keylist.begin(); it != keylist.end(); it++) {
1068 if ((cp = tqsl_cert_new()) == NULL) {
1069 tqslTrace("tqsl_selectCertificates", "error making new cert - %s", tqsl_openssl_error());
1070 goto end;
1071 }
1072 crq = reinterpret_cast<TQSL_CERT_REQ *>(tqsl_calloc(1, sizeof(TQSL_CERT_REQ)));
1073 if (crq != NULL) {
1074 tQSL_Error = TQSL_BUFFER_ERROR;
1075 if (!safe_strncpy(crq->providerName, (*it)["TQSL_CRQ_PROVIDER"].c_str(), sizeof crq->providerName))
1076 goto end;
1077 if (!safe_strncpy(crq->providerUnit, (*it)["TQSL_CRQ_PROVIDER_UNIT"].c_str(), sizeof crq->providerUnit))
1078 goto end;
1079 if (!safe_strncpy(crq->callSign, (*it)["CALLSIGN"].c_str(), sizeof crq->callSign))
1080 goto end;
1081 if (!safe_strncpy(crq->emailAddress, (*it)["TQSL_CRQ_EMAIL"].c_str(), sizeof crq->emailAddress))
1082 goto end;
1083 if (!safe_strncpy(crq->address1, (*it)["TQSL_CRQ_ADDRESS1"].c_str(), sizeof crq->address1))
1084 goto end;
1085 if (!safe_strncpy(crq->address2, (*it)["TQSL_CRQ_ADDRESS2"].c_str(), sizeof crq->address2))
1086 goto end;
1087 if (!safe_strncpy(crq->city, (*it)["TQSL_CRQ_CITY"].c_str(), sizeof crq->city))
1088 goto end;
1089 if (!safe_strncpy(crq->state, (*it)["TQSL_CRQ_STATE"].c_str(), sizeof crq->state))
1090 goto end;
1091 if (!safe_strncpy(crq->postalCode, (*it)["TQSL_CRQ_POSTAL"].c_str(), sizeof crq->postalCode))
1092 goto end;
1093 if (!safe_strncpy(crq->country, (*it)["TQSL_CRQ_COUNTRY"].c_str(), sizeof crq->country))
1094 goto end;
1095 crq->dxccEntity = strtol((*it)["TQSL_CRQ_DXCC_ENTITY"].c_str(), NULL, 10);
1096 tqsl_initDate(&(crq->qsoNotBefore), (*it)["TQSL_CRQ_QSO_NOT_BEFORE"].c_str());
1097 tqsl_initDate(&(crq->qsoNotAfter), (*it)["TQSL_CRQ_QSO_NOT_AFTER"].c_str());
1098 tQSL_Error = 0;
1099 }
1100 cp->crq = crq;
1101 int len = strlen((*it)["PUBLIC_KEY"].c_str());
1102 if (len) {
1103 cp->pubkey = new char[len+1];
1104 strncpy(cp->pubkey, (*it)["PUBLIC_KEY"].c_str(), len+1);
1105 }
1106 len = strlen((*it)["PRIVATE_KEY"].c_str());
1107 if (len) {
1108 cp->privkey = new char[len+1];
1109 strncpy(cp->privkey, (*it)["PRIVATE_KEY"].c_str(), len+1);
1110 }
1111 cp->keyonly = 1;
1112 (*certlist)[i++] = TQSL_OBJ_TO_API(cp);
1113 }
1114
1115 if (keyerror) { // If an error happened with private key scan
1116 tQSL_Error = savedError; // Restore the error status from that
1117 tQSL_Errno = savedErrno;
1118 rval = 1;
1119 } else {
1120 rval = 0;
1121 }
1122 goto end;
1123 err:
1124 tQSL_Error = TQSL_OPENSSL_ERROR;
1125 end:
1126 if (selcerts != NULL)
1127 sk_X509_free(selcerts);
1128 if (bio != NULL)
1129 BIO_free(bio);
1130 if (pubkey != NULL)
1131 EVP_PKEY_free(pubkey);
1132 if (curkey != NULL)
1133 EVP_PKEY_free(curkey);
1134 return rval;
1135 }
1136
1137 DLLEXPORT int CALLCONVENTION
1138 tqsl_selectCACertificates(tQSL_Cert **certlist, int *ncerts, const char *type) {
1139 TQSL_X509_STACK *cacerts = NULL;
1140 int rval = 1;
1141 char path[256];
1142 int i;
1143 X509 *x;
1144 tqsl_cert *cp;
1145 vector< map<string, string> > keylist;
1146 vector< map<string, string> >::iterator it;
1147 tqslTrace("tqsl_selectCACertificates", NULL);
1148
1149 if (tqsl_init())
1150 return 1;
1151 if (certlist == NULL || ncerts == NULL) {
1152 tqslTrace("tqsl_selectCACertificates", "arg error certlist=0x%lx, ncerts=0x%lx", certlist, ncerts);
1153 tQSL_Error = TQSL_ARGUMENT_ERROR;
1154 return 1;
1155 }
1156
1157 /* Get the certs from the cert store */
1158 tqsl_make_cert_path(type, path, sizeof path);
1159 cacerts = tqsl_ssl_load_certs_from_file(path);
1160 if (cacerts == NULL) {
1161 if (tQSL_Error == TQSL_OPENSSL_ERROR) {
1162 tqslTrace("tqsl_selectCACertificates", "cacerts openssl error");
1163 return 1;
1164 }
1165 }
1166 *ncerts = (cacerts ? sk_X509_num(cacerts) : 0) + keylist.size();
1167 *certlist = reinterpret_cast<tQSL_Cert *>(tqsl_calloc(*ncerts, sizeof(tQSL_Cert)));
1168 if (cacerts != NULL) {
1169 for (i = 0; i < sk_X509_num(cacerts); i++) {
1170 x = sk_X509_value(cacerts, i);
1171 if ((cp = tqsl_cert_new()) == NULL) {
1172 tqslTrace("tqsl_selectCACertificates", "cert_new error %s", tqsl_openssl_error());
1173 goto end;
1174 }
1175 cp->cert = X509_dup(x);
1176 (*certlist)[i] = TQSL_OBJ_TO_API(cp);
1177 }
1178 }
1179 rval = 0;
1180 end:
1181 if (cacerts != NULL)
1182 sk_X509_free(cacerts);
1183 return rval;
1184 }
1185
1186 DLLEXPORT int CALLCONVENTION
1187 tqsl_getCertificateKeyOnly(tQSL_Cert cert, int *keyonly) {
1188 tqslTrace("tqsl_getCertificateKeyOnly", "cert=0x%lx, keyonly=0x%lx", cert, keyonly);
1189 if (tqsl_init())
1190 return 1;
1191 if (cert == NULL || keyonly == NULL || !tqsl_cert_check(TQSL_API_TO_CERT(cert), false)) {
1192 tqslTrace("tqsl_getCertificateKeyOnly", "arg error");
1193 tQSL_Error = TQSL_ARGUMENT_ERROR;
1194 return 1;
1195 }
1196 *keyonly = TQSL_API_TO_CERT(cert)->keyonly;
1197 return 0;
1198 }
1199
1200 DLLEXPORT int CALLCONVENTION
1201 tqsl_getCertificateEncoded(tQSL_Cert cert, char *buf, int bufsiz) {
1202 BIO *bio = NULL;
1203 int len;
1204 char *cp;
1205 int rval = 1;
1206 tqslTrace("tqsl_getCertificateEncoded", NULL);
1207
1208 if (tqsl_init())
1209 return 1;
1210 if (cert == NULL || buf == NULL || !tqsl_cert_check(TQSL_API_TO_CERT(cert))) {
1211 tqslTrace("tqsl_getCertificateEncoded", "arg error cert=0x%lx, buf=0x%lx", cert, buf);
1212 tQSL_Error = TQSL_ARGUMENT_ERROR;
1213 return 1;
1214 }
1215 if ((bio = BIO_new(BIO_s_mem())) == NULL) {
1216 tqslTrace("tqsl_getCertificateEncoded", "bio_new err %s", tqsl_openssl_error());
1217 goto err;
1218 }
1219 if (!PEM_write_bio_X509(bio, TQSL_API_TO_CERT(cert)->cert)) {
1220 tqslTrace("tqsl_getCertificateEncoded", "pem_write_bio err %s", tqsl_openssl_error());
1221 goto err;
1222 }
1223 len = static_cast<int>(BIO_get_mem_data(bio, &cp));
1224 if (len < bufsiz) {
1225 memcpy(buf, cp, len);
1226 buf[len] = 0;
1227 } else {
1228 tqslTrace("tqsl_getCertificateEncoded", "buffer error %d needed %d there", len, bufsiz);
1229 tQSL_Error = TQSL_BUFFER_ERROR;
1230 goto end;
1231 }
1232 rval = 0;
1233 goto end;
1234 err:
1235 tQSL_Error = TQSL_OPENSSL_ERROR;
1236 end:
1237 if (bio != NULL)
1238 BIO_free(bio);
1239 return rval;
1240 }
1241
1242 DLLEXPORT int CALLCONVENTION
1243 tqsl_getKeyEncoded(tQSL_Cert cert, char *buf, int bufsiz) {
1244 BIO *b64 = NULL;
1245 BIO *bio = NULL;
1246 BIO *out = NULL;
1247 char callsign[40];
1248 long len;
1249 char *cp;
1250 vector< map<string, string> > keylist;
1251 vector< map<string, string> >::iterator it;
1252 EVP_PKEY *pubkey = NULL;
1253 EVP_PKEY *curkey = NULL;
1254 tqslTrace("tqsl_getKeyEncoded", NULL);
1255
1256 if (tqsl_init())
1257 return 1;
1258 if (cert == NULL || buf == NULL || !tqsl_cert_check(TQSL_API_TO_CERT(cert), false)) {
1259 tqslTrace("tqsl_getKeyEncoded", "arg error cert=0x%lx, buf=0x%lx", cert, buf);
1260 tQSL_Error = TQSL_ARGUMENT_ERROR;
1261 return 1;
1262 }
1263 tQSL_Error = TQSL_OPENSSL_ERROR;
1264 // If it's 'keyonly', then there's no public key - use the one in the cert.
1265 if (TQSL_API_TO_CERT(cert)->keyonly) {
1266 if (TQSL_API_TO_CERT(cert)->privkey == 0) {
1267 tqslTrace("tqsl_getKeyEncoded", "arg error no private key");
1268 tQSL_Error = TQSL_ARGUMENT_ERROR;
1269 return 1;
1270 }
1271 strncpy(callsign, TQSL_API_TO_CERT(cert)->crq->callSign, sizeof callsign);
1272 b64 = BIO_new(BIO_f_base64());
1273 out = BIO_new(BIO_s_mem());
1274 out = BIO_push(b64, out);
1275 tQSL_Error = TQSL_SYSTEM_ERROR;
1276 if (tqsl_bio_write_adif_field(out, "CALLSIGN", 0, (const unsigned char *)callsign, -1)) {
1277 tqslTrace("tqsl_getKeyEncoded", "write_adif_field error %d", tQSL_Error);
1278 return 1;
1279 }
1280 if (tqsl_bio_write_adif_field(out, "PRIVATE_KEY", 0, (const unsigned char *)TQSL_API_TO_CERT(cert)->privkey, -1)) {
1281 tqslTrace("tqsl_getKeyEncoded", "write_adif_field error %d", tQSL_Error);
1282 return 1;
1283 }
1284 if (tqsl_bio_write_adif_field(out, "PUBLIC_KEY", 0, (const unsigned char *)TQSL_API_TO_CERT(cert)->pubkey, -1)) {
1285 tqslTrace("tqsl_getKeyEncoded", "write_adif_field error %d", tQSL_Error);
1286 return 1;
1287 }
1288 char numbuf[10];
1289 snprintf(numbuf, sizeof numbuf, "%d", TQSL_API_TO_CERT(cert)->crq->dxccEntity);
1290 if (tqsl_bio_write_adif_field(out, "TQSL_CRQ_DXCC_ENTITY", 0, (const unsigned char *)numbuf, -1)) {
1291 tqslTrace("tqsl_getKeyEncoded", "write_adif_field error %d", tQSL_Error);
1292 return 1;
1293 }
1294 if (tqsl_bio_write_adif_field(out, "TQSL_CRQ_PROVIDER", 0, (const unsigned char *)TQSL_API_TO_CERT(cert)->crq->providerName, -1)) {
1295 tqslTrace("tqsl_getKeyEncoded", "write_adif_field error %d", tQSL_Error);
1296 return 1;
1297 }
1298 if (tqsl_bio_write_adif_field(out, "TQSL_CRQ_PROVIDER_UNIT", 0, (const unsigned char *)TQSL_API_TO_CERT(cert)->crq->providerUnit, -1)) {
1299 tqslTrace("tqsl_getKeyEncoded", "write_adif_field error %d", tQSL_Error);
1300 return 1;
1301 }
1302 if (tqsl_bio_write_adif_field(out, "TQSL_CRQ_EMAIL", 0, (const unsigned char *)TQSL_API_TO_CERT(cert)->crq->emailAddress, -1)) {
1303 tqslTrace("tqsl_getKeyEncoded", "write_adif_field error %d", tQSL_Error);
1304 return 1;
1305 }
1306 if (tqsl_bio_write_adif_field(out, "TQSL_CRQ_ADDRESS1", 0, (const unsigned char *)TQSL_API_TO_CERT(cert)->crq->address1, -1)) {
1307 tqslTrace("tqsl_getKeyEncoded", "write_adif_field error %d", tQSL_Error);
1308 return 1;
1309 }
1310 if (tqsl_bio_write_adif_field(out, "TQSL_CRQ_ADDRESS2", 0, (const unsigned char *)TQSL_API_TO_CERT(cert)->crq->address2, -1)) {
1311 tqslTrace("tqsl_getKeyEncoded", "write_adif_field error %d", tQSL_Error);
1312 return 1;
1313 }
1314 if (tqsl_bio_write_adif_field(out, "TQSL_CRQ_CITY", 0, (const unsigned char *)TQSL_API_TO_CERT(cert)->crq->city, -1)) {
1315 tqslTrace("tqsl_getKeyEncoded", "write_adif_field error %d", tQSL_Error);
1316 return 1;
1317 }
1318 if (tqsl_bio_write_adif_field(out, "TQSL_CRQ_STATE", 0, (const unsigned char *)TQSL_API_TO_CERT(cert)->crq->state, -1)) {
1319 tqslTrace("tqsl_getKeyEncoded", "write_adif_field error %d", tQSL_Error);
1320 return 1;
1321 }
1322 if (tqsl_bio_write_adif_field(out, "TQSL_CRQ_POSTAL", 0, (const unsigned char *)TQSL_API_TO_CERT(cert)->crq->postalCode, -1)) {
1323 tqslTrace("tqsl_getKeyEncoded", "write_adif_field error %d", tQSL_Error);
1324 return 1;
1325 }
1326 if (tqsl_bio_write_adif_field(out, "TQSL_CRQ_COUNTRY", 0, (const unsigned char *)TQSL_API_TO_CERT(cert)->crq->country, -1)) {
1327 tqslTrace("tqsl_getKeyEncoded", "write_adif_field error %d", tQSL_Error);
1328 return 1;
1329 }
1330 char datebuf[20];
1331 tqsl_convertDateToText(&(TQSL_API_TO_CERT(cert)->crq->qsoNotAfter), datebuf, sizeof datebuf);
1332 if (tqsl_bio_write_adif_field(out, "TQSL_CRQ_QSO_NOT_AFTER", 0, (const unsigned char *)datebuf, -1)) {
1333 tqslTrace("tqsl_getKeyEncoded", "write_adif_field error %d", tQSL_Error);
1334 tQSL_Error = TQSL_OPENSSL_ERROR;
1335 return 1;
1336 }
1337 tqsl_convertDateToText(&(TQSL_API_TO_CERT(cert)->crq->qsoNotBefore), datebuf, sizeof datebuf);
1338 if (tqsl_bio_write_adif_field(out, "TQSL_CRQ_QSO_NOT_BEFORE", 0, (const unsigned char *)datebuf, -1)) {
1339 tqslTrace("tqsl_getKeyEncoded", "write_adif_field error %d", tQSL_Error);
1340 tQSL_Error = TQSL_OPENSSL_ERROR;
1341 return 1;
1342 }
1343 tqsl_bio_write_adif_field(out, "eor", 0, NULL, 0);
1344 if (BIO_flush(out) != 1) {
1345 tQSL_Error = TQSL_CUSTOM_ERROR;
1346 strncpy(tQSL_CustomError, "Error encoding certificate", sizeof tQSL_CustomError);
1347 BIO_free_all(out);
1348 tqslTrace("tqsl_getKeyEncoded", "BIO_flush error %s", tqsl_openssl_error());
1349 return 1;
1350 }
1351
1352 len = BIO_get_mem_data(out, &cp);
1353 if (len > bufsiz) {
1354 tQSL_Error = TQSL_CUSTOM_ERROR;
1355 snprintf(tQSL_CustomError, sizeof tQSL_CustomError, "Private key buffer size %d is too small - %ld needed", bufsiz, len);
1356 BIO_free_all(out);
1357 tqslTrace("tqsl_getKeyEncoded", "buffer size err: %s", tQSL_CustomError);
1358 return 1;
1359 }
1360 memcpy(buf, cp, len);
1361 buf[len] = '\0';
1362 BIO_free_all(out);
1363 return 0;
1364 }
1365
1366 if (tqsl_getCertificateCallSign(cert, callsign, sizeof callsign)) {
1367 tqslTrace("tqsl_getKeyEncoded", "Error getting callsign %d", tQSL_Error);
1368 return 1;
1369 }
1370 if (tqsl_make_key_list(keylist)) {
1371 tqslTrace("tqsl_getKeyEncoded", "Error making keylist %d", tQSL_Error);
1372 tQSL_Error = TQSL_SYSTEM_ERROR;
1373 return 1;
1374 }
1375
1376 if ((pubkey = X509_get_pubkey(TQSL_API_TO_CERT(cert)->cert)) == 0) {
1377 tqslTrace("tqsl_getKeyEncoded", "Error getting pubkey %d", tQSL_Error);
1378 tQSL_Error = TQSL_OPENSSL_ERROR;
1379 return 1;
1380 }
1381 // Find the matching private key
1382 for (it = keylist.begin(); it != keylist.end(); it++) {
1383 string& keystr = (*it)["PUBLIC_KEY"];
1384 if ((bio = BIO_new_mem_buf(static_cast<void *>(const_cast<char *>(keystr.c_str())), keystr.length())) == NULL) {
1385 tqslTrace("tqsl_getKeyEncoded", "Error getting buffer %s", tqsl_openssl_error());
1386 tQSL_Error = TQSL_OPENSSL_ERROR;
1387 return 1;
1388 }
1389 if ((curkey = PEM_read_bio_PUBKEY(bio, NULL, NULL, NULL)) == NULL) {
1390 BIO_free(bio);
1391 tqslTrace("tqsl_getKeyEncoded", "Error reading PUBKEY %s", tqsl_openssl_error());
1392 tQSL_Error = TQSL_OPENSSL_ERROR;
1393 return 1;
1394 }
1395 BIO_free(bio);
1396 bio = NULL;
1397
1398 if (EVP_PKEY_cmp(curkey, pubkey) == 1) {
1399 // This is the matching private key. Let's feed it back.
1400 EVP_PKEY_free(curkey);
1401 curkey = NULL;
1402 EVP_PKEY_free(pubkey);
1403 pubkey = NULL;
1404 b64 = BIO_new(BIO_f_base64());
1405 out = BIO_new(BIO_s_mem());
1406 out = BIO_push(b64, out);
1407 map<string, string>::iterator mit;
1408 for (mit = it->begin(); mit != it->end(); mit++) {
1409 if (tqsl_bio_write_adif_field(out, mit->first.c_str(), 0, (const unsigned char *)mit->second.c_str(), -1)) {
1410 tQSL_Error = TQSL_SYSTEM_ERROR;
1411 tqslTrace("tqsl_getKeyEncoded", "Error writing field %s", tqsl_openssl_error());
1412 return 1;
1413 }
1414 }
1415 tqsl_bio_write_adif_field(out, "eor", 0, NULL, 0);
1416 if (BIO_flush(out) != 1) {
1417 tQSL_Error = TQSL_CUSTOM_ERROR;
1418 tqslTrace("tqsl_getKeyEncoded", "Error flushing write %s", tqsl_openssl_error());
1419 strncpy(tQSL_CustomError, "Error encoding certificate", sizeof tQSL_CustomError);
1420 BIO_free_all(out);
1421 return 1;
1422 }
1423
1424 len = BIO_get_mem_data(out, &cp);
1425 if (len > bufsiz) {
1426 tQSL_Error = TQSL_CUSTOM_ERROR;
1427 snprintf(tQSL_CustomError, sizeof tQSL_CustomError, "Private key buffer size %d is too small - %ld needed", bufsiz, len);
1428 tqslTrace("tqsl_getKeyEncoded", "Buffer err %s", tQSL_CustomError);
1429 BIO_free_all(out);
1430 return 1;
1431 }
1432 memcpy(buf, cp, len);
1433 buf[len] = '\0';
1434 BIO_free_all(out);
1435 return 0;
1436 } else {
1437 EVP_PKEY_free(curkey);
1438 curkey = NULL;
1439 }
1440 }
1441 if (pubkey != NULL)
1442 EVP_PKEY_free(pubkey);
1443 tqslTrace("tqsl_getKeyEncoded", "private key not found");
1444 tQSL_Error = TQSL_CUSTOM_ERROR;
1445 snprintf(tQSL_CustomError, sizeof tQSL_CustomError, "Private key not found for callsign %s", callsign);
1446 return 1; // Private key not found
1447 }
1448
1449 DLLEXPORT int CALLCONVENTION
1450 tqsl_importKeyPairEncoded(const char *callsign, const char *type, const char *keybuf, const char *certbuf) {
1451 BIO *in = NULL;
1452 BIO *b64 = NULL;
1453 BIO *out = NULL;
1454 BIO *pub = NULL;
1455 X509 *cert;
1456 char path[256];
1457 char biobuf[4096];
1458 int cb = 0;
1459 tqslTrace("tqsl_importKeyPairEncoded", NULL);
1460
1461 if (tqsl_init())
1462 return 1;
1463 if (certbuf == NULL || type == NULL) {
1464 tqslTrace("tqsl_importKeyPairEncoded", "arg error certbuf=0x%lx, type=0x%lx", certbuf, type);
1465 tQSL_Error = TQSL_ARGUMENT_ERROR;
1466 return 1;
1467 }
1468 if (strcmp(type, "user") == 0) {
1469 if (keybuf == NULL) {
1470 tqslTrace("tqsl_importKeyPairEncoded", "arg error user cert keybuf null");
1471 tQSL_Error = TQSL_ARGUMENT_ERROR;
1472 return 1;
1473 }
1474 cb = TQSL_CERT_CB_USER;
1475 } else if (strcmp(type, "root") == 0) {
1476 cb = TQSL_CERT_CB_ROOT;
1477 } else if (strcmp(type, "authorities") == 0) {
1478 cb = TQSL_CERT_CB_CA;
1479 } else {
1480 tqslTrace("tqsl_importKeyPairEncoded", "arg error type unknown");
1481 tQSL_Error = TQSL_ARGUMENT_ERROR;
1482 return 1;
1483 }
1484 if (keybuf) {
1485 if (!tqsl_make_key_path(callsign, path, sizeof path)) {
1486 goto noprv;
1487 }
1488
1489 in = BIO_new_mem_buf(static_cast<void *>(const_cast<char *>(keybuf)), strlen(keybuf));
1490 if (in == NULL) {
1491 goto noprv;
1492 }
1493
1494 b64 = BIO_new(BIO_f_base64());
1495 in = BIO_push(b64, in);
1496
1497 size_t bloblen;
1498 bloblen = BIO_read(in, biobuf, strlen(keybuf));
1499
1500 // Now is there a private key already with this serial?
1501 char *pubkey = strstr(biobuf, "-----BEGIN PUBLIC KEY-----");
1502 char *endpub = strstr(biobuf, "-----END PUBLIC KEY-----");
1503 int publen = endpub - pubkey + strlen("-----END PUBLIC KEY-----");
1504 if (pubkey) {
1505 EVP_PKEY *new_key = NULL;
1506 if ((pub = BIO_new_mem_buf(reinterpret_cast<void *>(pubkey), publen)) == NULL) {
1507 goto noprv;
1508 }
1509 if ((new_key = PEM_read_bio_PUBKEY(pub, NULL, NULL, NULL)) == NULL) {
1510 goto noprv;
1511 }
1512 BIO_free(pub);
1513 pub = 0;
1514 if (!tqsl_key_exists(callsign, new_key)) {
1515 if (tqsl_open_key_file(path)) {
1516 out = BIO_new_file(path, "a");
1517 if (!out) {
1518 tQSL_Error = TQSL_SYSTEM_ERROR;
1519 tQSL_Errno = errno;
1520 snprintf(tQSL_CustomError, sizeof tQSL_CustomError, "Unable to open private key %s: %s",
1521 path, strerror(errno));
1522 tqslTrace("tqsl_importKeyPairEncoded", "new_file err %s", tQSL_CustomError);
1523 goto noprv;
1524 }
1525 BIO_write(out, biobuf, bloblen);
1526 BIO_free_all(out);
1527 }
1528 BIO_free_all(in);
1529 }
1530 }
1531 } // Import of private key
1532
1533 noprv:
1534 if (strlen(certbuf) == 0) // Keyonly 'certificates'
1535 return 0;
1536
1537 // Now process the certificate
1538 in = BIO_new_mem_buf(static_cast<void *>(const_cast<char *>(certbuf)), strlen(certbuf));
1539 if (in == NULL) {
1540 tqslTrace("tqsl_importKeyPairEncoded", "cert new_mem_buf err %s", tqsl_openssl_error());
1541 tQSL_Error = TQSL_OPENSSL_ERROR;
1542 return 1;
1543 }
1544 cert = PEM_read_bio_X509(in, NULL, NULL, NULL);
1545 BIO_free(in);
1546 if (cert == NULL) {
1547 tqslTrace("tqsl_importKeyPairEncoded", "read_bio_x509 err %s", tqsl_openssl_error());
1548 tQSL_Error = TQSL_OPENSSL_ERROR;
1549 return 1;
1550 }
1551 return tqsl_store_cert(certbuf, cert, type, cb, true, NULL, NULL);
1552 }
1553
1554 DLLEXPORT int CALLCONVENTION
1555 tqsl_getCertificateCallSign(tQSL_Cert cert, char *buf, int bufsiz) {
1556 char nbuf[40];
1557 TQSL_X509_NAME_ITEM item;
1558
1559 tqslTrace("tqsl_getCertificateCallSign", NULL);
1560 if (tqsl_init())
1561 return 1;
1562 if (cert == NULL || buf == NULL || !tqsl_cert_check(TQSL_API_TO_CERT(cert), false)) {
1563 tqslTrace("tqsl_getCertificateCallSign", "arg err cert=0x%lx buf=0x%lx", cert, buf);
1564 tQSL_Error = TQSL_ARGUMENT_ERROR;
1565 return 1;
1566 }
1567 if (TQSL_API_TO_CERT(cert)->keyonly && TQSL_API_TO_CERT(cert)->crq) {
1568 // Handle the key-only case
1569 if (bufsiz <= static_cast<int>(strlen(TQSL_API_TO_CERT(cert)->crq->callSign))) {
1570 tqslTrace("tqsl_getCertificateCallSign", "bufsiz=%d, needed=%d", bufsiz, static_cast<int>(strlen(TQSL_API_TO_CERT(cert)->crq->callSign)));
1571 tQSL_Error = TQSL_BUFFER_ERROR;
1572 return 1;
1573 }
1574 strncpy(buf, TQSL_API_TO_CERT(cert)->crq->callSign, bufsiz);
1575 tqslTrace("tqsl_getCertificateCallSign", "KeyOnly, call=%s", buf);
1576 return 0;
1577 }
1578 item.name_buf = nbuf;
1579 item.name_buf_size = sizeof nbuf;
1580 item.value_buf = buf;
1581 item.value_buf_size = bufsiz;
1582 int ret = tqsl_cert_get_subject_name_entry(TQSL_API_TO_CERT(cert)->cert, "AROcallsign", &item);
1583 tqslTrace("tqsl_getCertificateCallSign", "Result=%d, call=%s", ret, buf);
1584 return !ret;
1585 }
1586
1587
1588 DLLEXPORT int CALLCONVENTION
1589 tqsl_getCertificateAROName(tQSL_Cert cert, char *buf, int bufsiz) {
1590 char nbuf[40];
1591 TQSL_X509_NAME_ITEM item;
1592
1593 tqslTrace("tqsl_getCertificateAROName", NULL);
1594 if (tqsl_init())
1595 return 1;
1596 if (cert == NULL || buf == NULL || !tqsl_cert_check(TQSL_API_TO_CERT(cert))) {
1597 tqslTrace("tqsl_getCertificateAROName", "cert=0x%lx, buf=0x%lx", cert, buf);
1598 tQSL_Error = TQSL_ARGUMENT_ERROR;
1599 return 1;
1600 }
1601 item.name_buf = nbuf;
1602 item.name_buf_size = sizeof nbuf;
1603 item.value_buf = buf;
1604 item.value_buf_size = bufsiz;
1605 return !tqsl_cert_get_subject_name_entry(TQSL_API_TO_CERT(cert)->cert, "commonName", &item);
1606 }
1607
1608
1609 DLLEXPORT int CALLCONVENTION
1610 tqsl_getCertificateEmailAddress(tQSL_Cert cert, char *buf, int bufsiz) {
1611 char nbuf[40];
1612 TQSL_X509_NAME_ITEM item;
1613
1614 tqslTrace("tqsl_getCertificateEmailAddress", NULL);
1615 if (tqsl_init())
1616 return 1;
1617 if (cert == NULL || buf == NULL || !tqsl_cert_check(TQSL_API_TO_CERT(cert))) {
1618 tqslTrace("tqsl_getCertificateEmailAddress", "arg err cert=0x%lx, buf=0x%lx", cert, buf);
1619 tQSL_Error = TQSL_ARGUMENT_ERROR;
1620 return 1;
1621 }
1622 item.name_buf = nbuf;
1623 item.name_buf_size = sizeof nbuf;
1624 item.value_buf = buf;
1625 item.value_buf_size = bufsiz;
1626 return !tqsl_cert_get_subject_name_entry(TQSL_API_TO_CERT(cert)->cert, "emailAddress", &item);
1627 }
1628
1629 DLLEXPORT int CALLCONVENTION
1630 tqsl_getCertificateSerial(tQSL_Cert cert, long *serial) {
1631 tqslTrace("tqsl_getCertificateSerial", NULL);
1632 if (tqsl_init())
1633 return 1;
1634 if (cert == NULL || serial == NULL || !tqsl_cert_check(TQSL_API_TO_CERT(cert))) {
1635 tqslTrace("tqsl_getCertificateSerial", "arg err cert=0x%lx, serial=0x%lx", cert, serial);
1636 tQSL_Error = TQSL_ARGUMENT_ERROR;
1637 return 1;
1638 }
1639 *serial = ASN1_INTEGER_get(X509_get_serialNumber(TQSL_API_TO_CERT(cert)->cert));
1640 return 0;
1641 }
1642
1643 DLLEXPORT int CALLCONVENTION
1644 tqsl_getCertificateSerialExt(tQSL_Cert cert, char *serial, int serialsiz) {
1645 tqslTrace("tqsl_getCertificateSerialExt", NULL);
1646 if (tqsl_init())
1647 return 1;
1648 if (cert == NULL || serial == NULL || !tqsl_cert_check(TQSL_API_TO_CERT(cert)) || serialsiz < 1) {
1649 tqslTrace("tqsl_getCertificateSerialExt", "arg err cert=0x%lx, serial=0x%lx", cert, serial);
1650 tQSL_Error = TQSL_ARGUMENT_ERROR;
1651 return 1;
1652 }
1653 BIGNUM *bn = BN_new();
1654 ASN1_INTEGER_to_BN(X509_get_serialNumber(TQSL_API_TO_CERT(cert)->cert), bn);
1655 char *s = BN_bn2hex(bn);
1656 strncpy(serial, s, serialsiz);
1657 serial[serialsiz-1] = 0;
1658 OPENSSL_free(s);
1659 BN_free(bn);
1660 return 0;
1661 }
1662
1663 DLLEXPORT int CALLCONVENTION
1664 tqsl_getCertificateSerialLength(tQSL_Cert cert) {
1665 int rval;
1666 tqslTrace("tqsl_getCertificateSerialLength", NULL);
1667 if (tqsl_init())
1668 return 1;
1669 if (cert == NULL) {
1670 tqslTrace("tqsl_getCertificateSerialLength", "arg error,cert=null");
1671 tQSL_Error = TQSL_ARGUMENT_ERROR;
1672 return 1;
1673 }
1674 BIGNUM *bn = BN_new();
1675 ASN1_INTEGER_to_BN(X509_get_serialNumber(TQSL_API_TO_CERT(cert)->cert), bn);
1676 char *s = BN_bn2hex(bn);
1677 rval = strlen(s);
1678 OPENSSL_free(s);
1679 BN_free(bn);
1680 return rval;
1681 }
1682
1683 DLLEXPORT int CALLCONVENTION
1684 tqsl_getCertificateIssuer(tQSL_Cert cert, char *buf, int bufsiz) {
1685 char *cp;
1686
1687 tqslTrace("tqsl_getCertificateIssuer", NULL);
1688 if (tqsl_init())
1689 return 1;
1690 if (cert == NULL || buf == NULL || !tqsl_cert_check(TQSL_API_TO_CERT(cert))) {
1691 tqslTrace("tqsl_getCertificateIssuer", "arg err cert=0x%lx, buf=0x%lx", cert, buf);
1692 tQSL_Error = TQSL_ARGUMENT_ERROR;
1693 return 1;
1694 }
1695 cp = X509_NAME_oneline(X509_get_issuer_name(TQSL_API_TO_CERT(cert)->cert), buf, bufsiz);
1696 if (cp == NULL) {
1697 tqslTrace("tqsl_getCertificateIssuer", "X509_NAME_oneline error %s", tqsl_openssl_error());
1698 tQSL_Error = TQSL_OPENSSL_ERROR;
1699 }
1700 return (cp == NULL);
1701 }
1702
1703 DLLEXPORT int CALLCONVENTION
1704 tqsl_getCertificateIssuerOrganization(tQSL_Cert cert, char *buf, int bufsiz) {
1705 char nbuf[40];
1706 TQSL_X509_NAME_ITEM item;
1707 X509_NAME *iss;
1708
1709 tqslTrace("tqsl_getCertificateIssuerOrganization", NULL);
1710 if (tqsl_init())
1711 return 1;
1712 if (cert == NULL || buf == NULL || !tqsl_cert_check(TQSL_API_TO_CERT(cert), false)) {
1713 tqslTrace("tqsl_getCertificateIssuerOrganization", "arg error cert=0x%lx buf=0x%lx", cert, buf);
1714 tQSL_Error = TQSL_ARGUMENT_ERROR;
1715 return 1;
1716 }
1717 if (TQSL_API_TO_CERT(cert)->keyonly && TQSL_API_TO_CERT(cert)->crq) {
1718 // Handle the key-only case
1719 if (bufsiz <= static_cast<int>(strlen(TQSL_API_TO_CERT(cert)->crq->providerName))) {
1720 tqslTrace("tqsl_getCertificateIssuerOrganization", "bufsiz error have=%d need=%d",
1721 bufsiz,
1722 static_cast<int>(strlen(TQSL_API_TO_CERT(cert)->crq->providerName)));
1723 tQSL_Error = TQSL_BUFFER_ERROR;
1724 return 1;
1725 }
1726 strncpy(buf, TQSL_API_TO_CERT(cert)->crq->providerName, bufsiz);
1727 return 0;
1728 }
1729 item.name_buf = nbuf;
1730 item.name_buf_size = sizeof nbuf;
1731 item.value_buf = buf;
1732 item.value_buf_size = bufsiz;
1733 if ((iss = X509_get_issuer_name(TQSL_API_TO_CERT(cert)->cert)) == NULL) {
1734 tqslTrace("tqsl_getCertificateIssuerOrganization", "get_issuer_name err %s", tqsl_openssl_error());
1735 tQSL_Error = TQSL_OPENSSL_ERROR;
1736 return 1;
1737 }
1738 return !tqsl_get_name_entry(iss, "organizationName", &item);
1739 }
1740
1741 DLLEXPORT int CALLCONVENTION
1742 tqsl_getCertificateIssuerOrganizationalUnit(tQSL_Cert cert, char *buf, int bufsiz) {
1743 char nbuf[40];
1744 TQSL_X509_NAME_ITEM item;
1745 X509_NAME *iss;
1746
1747 tqslTrace("tqsl_getCertificateIssuerOrganizationalUnit", NULL);
1748 if (tqsl_init())
1749 return 1;
1750 if (cert == NULL || buf == NULL || !tqsl_cert_check(TQSL_API_TO_CERT(cert), false)) {
1751 tqslTrace("tqsl_getCertificateIssuerOrganizationalUnit", "arg err cert=0x%lx, buf=0x%lx", cert, buf);
1752 tQSL_Error = TQSL_ARGUMENT_ERROR;
1753 return 1;
1754 }
1755 if (TQSL_API_TO_CERT(cert)->keyonly && TQSL_API_TO_CERT(cert)->crq) {
1756 // Handle the key-only case
1757 if (bufsiz <= static_cast<int>(strlen(TQSL_API_TO_CERT(cert)->crq->providerUnit))) {
1758 tqslTrace("tqsl_getCertificateIssuerOrganizationalUnit", "bufsize error have=%d need=%d",
1759 bufsiz,
1760 static_cast<int>(strlen(TQSL_API_TO_CERT(cert)->crq->providerUnit)));
1761 tQSL_Error = TQSL_BUFFER_ERROR;
1762 return 1;
1763 }
1764 strncpy(buf, TQSL_API_TO_CERT(cert)->crq->providerUnit, bufsiz);
1765 return 0;
1766 }
1767 item.name_buf = nbuf;
1768 item.name_buf_size = sizeof nbuf;
1769 item.value_buf = buf;
1770 item.value_buf_size = bufsiz;
1771 if ((iss = X509_get_issuer_name(TQSL_API_TO_CERT(cert)->cert)) == NULL) {
1772 tqslTrace("tqsl_getCertificateIssuerOrganizationalUnit", "get_issuer_name err %s", tqsl_openssl_error());
1773 tQSL_Error = TQSL_OPENSSL_ERROR;
1774 return 1;
1775 }
1776 return !tqsl_get_name_entry(iss, "organizationalUnitName", &item);
1777 }
1778
1779 DLLEXPORT int CALLCONVENTION
1780 tqsl_getCertificateQSONotBeforeDate(tQSL_Cert cert, tQSL_Date *date) {
1781 char datebuf[40];
1782 int len = (sizeof datebuf) -1;
1783 tqslTrace("tqsl_getCertificateQSONotBeforeDate", NULL);
1784
1785 if (tqsl_init())
1786 return 1;
1787 if (cert == NULL || date == NULL || !tqsl_cert_check(TQSL_API_TO_CERT(cert), false)) {
1788 tqslTrace("tqsl_getCertificateQSONotBeforeDate", "arg err cert=0x%lx date=0x%lx", cert, date);
1789 tQSL_Error = TQSL_ARGUMENT_ERROR;
1790 return 1;
1791 }
1792 if (TQSL_API_TO_CERT(cert)->keyonly && TQSL_API_TO_CERT(cert)->crq) {
1793 // Handle the key-only case
1794 *date = TQSL_API_TO_CERT(cert)->crq->qsoNotBefore;
1795 return 0;
1796 }
1797 if (tqsl_get_cert_ext(TQSL_API_TO_CERT(cert)->cert, "QSONotBeforeDate",
1798 (unsigned char *)datebuf, &len, NULL))
1799 return 1;
1800 datebuf[len] = 0;
1801 return tqsl_initDate(date, const_cast<char *>(datebuf));
1802 }
1803
1804 DLLEXPORT int CALLCONVENTION
1805 tqsl_getCertificateQSONotAfterDate(tQSL_Cert cert, tQSL_Date *date) {
1806 char datebuf[40];
1807 int len = (sizeof datebuf) -1;
1808 tqslTrace("tqsl_getCertificateQSONotAfterDate", NULL);
1809
1810 if (tqsl_init())
1811 return 1;
1812 if (cert == NULL || date == NULL || !tqsl_cert_check(TQSL_API_TO_CERT(cert), false)) {
1813 tqslTrace("tqsl_getCertificateQSONotAfterDate", "arg err cert=0x%lx date=0x%lx", cert, date);
1814 tQSL_Error = TQSL_ARGUMENT_ERROR;
1815 return 1;
1816 }
1817 if (TQSL_API_TO_CERT(cert)->keyonly && TQSL_API_TO_CERT(cert)->crq) {
1818 // Handle the key-only case
1819 *date = TQSL_API_TO_CERT(cert)->crq->qsoNotAfter;
1820 return 0;
1821 }
1822 if (tqsl_get_cert_ext(TQSL_API_TO_CERT(cert)->cert, "QSONotAfterDate",
1823 (unsigned char *)datebuf, &len, NULL))
1824 return 1;
1825 datebuf[len] = 0;
1826 return tqsl_initDate(date, const_cast<char *>(datebuf));
1827 }
1828
1829 DLLEXPORT int CALLCONVENTION
1830 tqsl_getCertificateNotBeforeDate(tQSL_Cert cert, tQSL_Date *date) {
1831 const ASN1_TIME *tm;
1832
1833 tqslTrace("tqsl_getCertificateNotBeforeDate", NULL);
1834 if (tqsl_init())
1835 return 1;
1836 if (cert == NULL || date == NULL || !tqsl_cert_check(TQSL_API_TO_CERT(cert))) {
1837 tqslTrace("tqsl_getCertificateNotBeforeDate", "arg err cert=0x%lx date=0x%lx", cert, date);
1838 tQSL_Error = TQSL_ARGUMENT_ERROR;
1839 return 1;
1840 }
1841 if (TQSL_API_TO_CERT(cert)->keyonly) {
1842 tqslTrace("tqsl_getCertificateNotBeforeDate", "Err:cert is keyonly");
1843 tQSL_Error = TQSL_CERT_KEY_ONLY;
1844 return 1;
1845 }
1846 if ((tm = X509_get_notBefore(TQSL_API_TO_CERT(cert)->cert)) == NULL) {
1847 tqslTrace("tqsl_getCertificateNotBeforeDate", "get_notBefore err %s", tqsl_openssl_error());
1848 tQSL_Error = TQSL_OPENSSL_ERROR;
1849 return 1;
1850 }
1851 return tqsl_get_asn1_date(tm, date);
1852 }
1853
1854 DLLEXPORT int CALLCONVENTION
1855 tqsl_getCertificateNotAfterDate(tQSL_Cert cert, tQSL_Date *date) {
1856 const ASN1_TIME *tm;
1857
1858 if (tqsl_init())
1859 return 1;
1860 if (cert == NULL || date == NULL || !tqsl_cert_check(TQSL_API_TO_CERT(cert))) {
1861 tqslTrace("tqsl_getCertificateNotAfterDate", "arg err cert=0x%lx date=0x%lx", cert, date);
1862 tQSL_Error = TQSL_ARGUMENT_ERROR;
1863 return 1;
1864 }
1865 if (TQSL_API_TO_CERT(cert)->keyonly) {
1866 tqslTrace("tqsl_getCertificateNotAfterDate", "Err:cert is keyonly");
1867 tQSL_Error = TQSL_CERT_KEY_ONLY;
1868 return 1;
1869 }
1870 if ((tm = X509_get_notAfter(TQSL_API_TO_CERT(cert)->cert)) == NULL) {
1871 tqslTrace("tqsl_getCertificateNotAfterDate", "get_notAfter err %s", tqsl_openssl_error());
1872 tQSL_Error = TQSL_OPENSSL_ERROR;
1873 return 1;
1874 }
1875 return tqsl_get_asn1_date(tm, date);
1876 }
1877
1878 DLLEXPORT int CALLCONVENTION
1879 tqsl_getCertificateDXCCEntity(tQSL_Cert cert, int *dxcc) {
1880 char buf[40];
1881 int len = sizeof buf;
1882 tqslTrace("tqsl_getCertificateDXCCEntity", NULL);
1883
1884 if (tqsl_init())
1885 return 1;
1886 if (cert == NULL || dxcc == NULL || !tqsl_cert_check(TQSL_API_TO_CERT(cert), false)) {
1887 tqslTrace("tqsl_getCertificateDXCCEntity", "arg err cert=0x%lx dxcc=0x%lx", cert, dxcc);
1888 tQSL_Error = TQSL_ARGUMENT_ERROR;
1889 return 1;
1890 }
1891 if (TQSL_API_TO_CERT(cert)->keyonly && TQSL_API_TO_CERT(cert)->crq) {
1892 // Handle the key-only case
1893 *dxcc = TQSL_API_TO_CERT(cert)->crq->dxccEntity;
1894 return 0;
1895 }
1896 if (tqsl_get_cert_ext(TQSL_API_TO_CERT(cert)->cert, "dxccEntity",
1897 (unsigned char *)buf, &len, NULL)) {
1898 tqslTrace("tqsl_getCertificateDXCCEntity", "Cert does not have dxcc extension");
1899 return 1;
1900 }
1901 *dxcc = strtol(buf, NULL, 10);
1902 return 0;
1903 }
1904
1905 DLLEXPORT int CALLCONVENTION
1906 tqsl_getCertificatePrivateKeyType(tQSL_Cert cert) {
1907 tqslTrace("tqsl_getCertificatePrivateKeyType", NULL);
1908
1909 if (tqsl_init())
1910 return 1;
1911 if (!tqsl_cert_check(TQSL_API_TO_CERT(cert), false)) {
1912 tqslTrace("tqsl_getCertificatePrivateKeyType", "arg err, bad cert");
1913 tQSL_Error = TQSL_ARGUMENT_ERROR;
1914 return 1;
1915 }
1916 if (tqsl_beginSigning(cert, const_cast<char *> (""), 0, 0)) { // Try to unlock the key using no password
1917 if (tQSL_Error == TQSL_PASSWORD_ERROR) {
1918 tqsl_getErrorString(); // Clear the error
1919 tqslTrace("tqsl_getCertificatePrivateKeyType", "password error - encrypted");
1920 return TQSL_PK_TYPE_ENC;
1921 }
1922 tqslTrace("tqsl_getCertificatePrivateKeyType", "other error");
1923 return TQSL_PK_TYPE_ERR;
1924 }
1925 tqslTrace("tqsl_getCertificatePrivateKeyType", "unencrypted");
1926 return TQSL_PK_TYPE_UNENC;
1927 }
1928
1929 DLLEXPORT void CALLCONVENTION
1930 tqsl_freeCertificate(tQSL_Cert cert) {
1931 if (cert == NULL) return;
1932 tqsl_cert_free(TQSL_API_TO_CERT(cert));
1933 }
1934
1935 DLLEXPORT void CALLCONVENTION
1936 tqsl_freeCertificateList(tQSL_Cert* list, int ncerts) {
1937 for (int i = 0; i < ncerts; i++)
1938 if (list[i]) tqsl_cert_free(TQSL_API_TO_CERT(list[i]));
1939 if (list) free(list);
1940 }
1941
1942 DLLEXPORT int CALLCONVENTION
1943 tqsl_beginSigning(tQSL_Cert cert, char *password, int(*pwcb)(char *, int, void *), void *userdata) {
1944 tqslTrace("tqsl_beginSigning", NULL);
1945
1946 if (tqsl_init())
1947 return 1;
1948 if (cert == NULL || !tqsl_cert_check(TQSL_API_TO_CERT(cert), false)) {
1949 tqslTrace("tqsl_beginSigning", "arg err cert=0x%lx", cert);
1950 tQSL_Error = TQSL_ARGUMENT_ERROR;
1951 return 1;
1952 }
1953 if (TQSL_API_TO_CERT(cert)->key != NULL)
1954 return 0;
1955 if (TQSL_API_TO_CERT(cert)->keyonly) {
1956 if (TQSL_API_TO_CERT(cert)->privkey == 0) {
1957 tqslTrace("tqsl_beginSigning", "can't sign, keyonly");
1958 tQSL_Error = TQSL_ARGUMENT_ERROR;
1959 return 1;
1960 }
1961 return tqsl_unlock_key(TQSL_API_TO_CERT(cert)->privkey, &(TQSL_API_TO_CERT(cert)->key),
1962 password, pwcb, userdata);
1963 }
1964 return tqsl_find_matching_key(TQSL_API_TO_CERT(cert)->cert, &(TQSL_API_TO_CERT(cert)->key),
1965 &(TQSL_API_TO_CERT(cert)->crq), password, pwcb, userdata);
1966 }
1967
1968 DLLEXPORT int CALLCONVENTION
1969 tqsl_getMaxSignatureSize(tQSL_Cert cert, int *sigsize) {
1970 tqslTrace("tqsl_getMaxSignatureSize", NULL);
1971
1972 if (tqsl_init())
1973 return 1;
1974 if (cert == NULL || sigsize == NULL || !tqsl_cert_check(TQSL_API_TO_CERT(cert))) {
1975 tqslTrace("tqsl_getMaxSignatureSize", "arg err cert=0x%lx, sigsize=0x%lx", cert, sigsize);
1976 tQSL_Error = TQSL_ARGUMENT_ERROR;
1977 return 1;
1978 }
1979 if (TQSL_API_TO_CERT(cert)->key == NULL) {
1980 tqslTrace("tqsl_getMaxSignatureSize", "arg err key=null");
1981 tQSL_Error = TQSL_SIGNINIT_ERROR;
1982 return 1;
1983 }
1984 *sigsize = EVP_PKEY_size(TQSL_API_TO_CERT(cert)->key);
1985 return 0;
1986 }
1987
1988 DLLEXPORT int CALLCONVENTION
1989 tqsl_checkSigningStatus(tQSL_Cert cert) {
1990 tqslTrace("tqsl_checkSigningStatus", NULL);
1991 if (tqsl_init())
1992 return 1;
1993 if (cert == NULL || !tqsl_cert_check(TQSL_API_TO_CERT(cert))) {
1994 tqslTrace("tqsl_checkSigningStatus", "arg err cert=0x%lx", cert);
1995 tQSL_Error = TQSL_ARGUMENT_ERROR;
1996 return 1;
1997 }
1998 if (TQSL_API_TO_CERT(cert)->key == NULL) {
1999 tqslTrace("tqsl_checkSigningStatus", "arg err no key");
2000 tQSL_Error = TQSL_SIGNINIT_ERROR;
2001 return 1;
2002 }
2003 return 0;
2004 }
2005
2006 DLLEXPORT int CALLCONVENTION
2007 tqsl_signDataBlock(tQSL_Cert cert, const unsigned char *data, int datalen, unsigned char *sig, int *siglen) {
2008 tqslTrace("tqsl_signDataBlock", NULL);
2009 if (tqsl_init())
2010 return 1;
2011 if (cert == NULL || data == NULL || sig == NULL || siglen == NULL || !tqsl_cert_check(TQSL_API_TO_CERT(cert))) {
2012 tqslTrace("tqsl_signDataBlock", "arg error cert=0x%lx data=0x%lx sig=0x%lx siglen=0x%lx", cert, data, sig, siglen);
2013 tQSL_Error = TQSL_ARGUMENT_ERROR;
2014 return 1;
2015 }
2016 EVP_MD_CTX *ctx = EVP_MD_CTX_create();
2017 if (ctx == NULL)
2018 return 1;
2019 unsigned int slen = *siglen;
2020
2021 if (TQSL_API_TO_CERT(cert)->key == NULL) {
2022 tqslTrace("tqsl_signDataBlock", "can't sign, no key");
2023 tQSL_Error = TQSL_SIGNINIT_ERROR;
2024 if (ctx)
2025 EVP_MD_CTX_destroy(ctx);
2026 return 1;
2027 }
2028 EVP_SignInit(ctx, EVP_sha1());
2029 EVP_SignUpdate(ctx, data, datalen);
2030 if (!EVP_SignFinal(ctx, sig, &slen, TQSL_API_TO_CERT(cert)->key)) {
2031 tqslTrace("tqsl_signDataBlock", "signing failed %s", tqsl_openssl_error());
2032 tQSL_Error = TQSL_OPENSSL_ERROR;
2033 if (ctx)
2034 EVP_MD_CTX_destroy(ctx);
2035 return 1;
2036 }
2037 *siglen = slen;
2038 if (ctx)
2039 EVP_MD_CTX_destroy(ctx);
2040 return 0;
2041 }
2042
2043 DLLEXPORT int CALLCONVENTION
2044 tqsl_verifyDataBlock(tQSL_Cert cert, const unsigned char *data, int datalen, unsigned char *sig, int siglen) {
2045 EVP_MD_CTX *ctx = EVP_MD_CTX_create();
2046
2047 unsigned int slen = siglen;
2048 tqslTrace("tqsl_verifyDataBlock", NULL);
2049
2050 if (ctx == NULL)
2051 return 1;
2052 if (tqsl_init())
2053 return 1;
2054 if (cert == NULL || data == NULL || sig == NULL || !tqsl_cert_check(TQSL_API_TO_CERT(cert))) {
2055 tqslTrace("tqsl_verifyDataBlock", "arg error cert=0x%lx data=0x%lx sig=0x%lx", cert, data, sig);
2056 tQSL_Error = TQSL_ARGUMENT_ERROR;
2057 if (ctx)
2058 EVP_MD_CTX_destroy(ctx);
2059 return 1;
2060 }
2061 if (TQSL_API_TO_CERT(cert)->key == NULL) {
2062 tqslTrace("tqsl_verifyDataBlock", "no key");
2063 tQSL_Error = TQSL_SIGNINIT_ERROR;
2064 if (ctx)
2065 EVP_MD_CTX_destroy(ctx);
2066 return 1;
2067 }
2068 EVP_VerifyInit(ctx, EVP_sha1());
2069 EVP_VerifyUpdate(ctx, data, datalen);
2070 if (EVP_VerifyFinal(ctx, sig, slen, TQSL_API_TO_CERT(cert)->key) <= 0) {
2071 tqslTrace("tqsl_verifyDataBlock", "verify fail %s", tqsl_openssl_error());
2072 tQSL_Error = TQSL_OPENSSL_ERROR;
2073 if (ctx)
2074 EVP_MD_CTX_destroy(ctx);
2075 return 1;
2076 }
2077 if (ctx)
2078 EVP_MD_CTX_destroy(ctx);
2079 return 0;
2080 }
2081
2082 DLLEXPORT int CALLCONVENTION
2083 tqsl_endSigning(tQSL_Cert cert) {
2084 tqslTrace("tqsl_endSigning", NULL);
2085
2086 if (tqsl_init())
2087 return 1;
2088 if (cert == NULL || !tqsl_cert_check(TQSL_API_TO_CERT(cert))) {
2089 tqslTrace("tqsl_endSigning", "arg err cert=0x%lx", cert);
2090 tQSL_Error = TQSL_ARGUMENT_ERROR;
2091 return 1;
2092 }
2093 if (TQSL_API_TO_CERT(cert)->key != NULL) {
2094 EVP_PKEY_free(TQSL_API_TO_CERT(cert)->key);
2095 TQSL_API_TO_CERT(cert)->key = NULL;
2096 }
2097 return 0;
2098 }
2099
2100 DLLEXPORT int CALLCONVENTION
2101 tqsl_getCertificateRequestAddress1(tQSL_Cert cert, char *buf, int bufsiz) {
2102 tqslTrace("tqsl_getCertificateRequestAddress1", NULL);
2103
2104 if (tqsl_check_crq_field(cert, buf, bufsiz)) {
2105 tqslTrace("tqsl_getCertificateRequestAddress1", "check fail");
2106 return 1;
2107 }
2108 strncpy(buf,
2109 (((TQSL_API_TO_CERT(cert)->crq)->address1) == NULL ? "" : (TQSL_API_TO_CERT(cert)->crq)->address1),
2110 bufsiz);
2111 return 0;
2112 }
2113
2114 DLLEXPORT int CALLCONVENTION
2115 tqsl_getCertificateRequestAddress2(tQSL_Cert cert, char *buf, int bufsiz) {
2116 tqslTrace("tqsl_getCertificateRequestAddress2", NULL);
2117
2118 if (tqsl_check_crq_field(cert, buf, bufsiz)) {
2119 tqslTrace("tqsl_getCertificateRequestAddress2", "check fail");
2120 return 1;
2121 }
2122 strncpy(buf,
2123 (((TQSL_API_TO_CERT(cert)->crq)->address2) == NULL ? "" : (TQSL_API_TO_CERT(cert)->crq)->address2),
2124 bufsiz);
2125 return 0;
2126 }
2127
2128 DLLEXPORT int CALLCONVENTION
2129 tqsl_getCertificateRequestCity(tQSL_Cert cert, char *buf, int bufsiz) {
2130 tqslTrace("tqsl_getCertificateRequestCity", NULL);
2131
2132 if (tqsl_check_crq_field(cert, buf, bufsiz)) {
2133 tqslTrace("tqsl_getCertificateRequestCity", "check fail");
2134 return 1;
2135 }
2136 strncpy(buf,
2137 (((TQSL_API_TO_CERT(cert)->crq)->city) == NULL ? "" : (TQSL_API_TO_CERT(cert)->crq)->city),
2138 bufsiz);
2139 return 0;
2140 }
2141
2142 DLLEXPORT int CALLCONVENTION
2143 tqsl_getCertificateRequestState(tQSL_Cert cert, char *buf, int bufsiz) {
2144 tqslTrace("tqsl_getCertificateRequestState", NULL);
2145 if (tqsl_check_crq_field(cert, buf, bufsiz)) {
2146 tqslTrace("tqsl_getCertificateRequestState", "check fail");
2147 return 1;
2148 }
2149 strncpy(buf,
2150 (((TQSL_API_TO_CERT(cert)->crq)->state) == NULL ? "" : (TQSL_API_TO_CERT(cert)->crq)->state),
2151 bufsiz);
2152 return 0;
2153 }
2154
2155 DLLEXPORT int CALLCONVENTION
2156 tqsl_getCertificateRequestPostalCode(tQSL_Cert cert, char *buf, int bufsiz) {
2157 tqslTrace("tqsl_getCertificateRequestPostalCode", NULL);
2158 if (tqsl_check_crq_field(cert, buf, bufsiz)) {
2159 tqslTrace("tqsl_getCertificateRequestPostalCode", "check fail");
2160 return 1;
2161 }
2162 strncpy(buf,
2163 (((TQSL_API_TO_CERT(cert)->crq)->postalCode) == NULL ? "" : (TQSL_API_TO_CERT(cert)->crq)->postalCode),
2164 bufsiz);
2165 return 0;
2166 }
2167
2168 DLLEXPORT int CALLCONVENTION
2169 tqsl_getCertificateRequestCountry(tQSL_Cert cert, char *buf, int bufsiz) {
2170 tqslTrace("tqsl_getCertificateRequestCountry", NULL);
2171 if (tqsl_check_crq_field(cert, buf, bufsiz)) {
2172 tqslTrace("tqsl_getCertificateRequestCountry", "check fail");
2173 return 1;
2174 }
2175 strncpy(buf,
2176 (((TQSL_API_TO_CERT(cert)->crq)->country) == NULL ? "" : (TQSL_API_TO_CERT(cert)->crq)->country),
2177 bufsiz);
2178 return 0;
2179 }
2180
2181 static int
2182 tqsl_add_bag_attribute(PKCS12_SAFEBAG *bag, const char *oidname, const string& value) {
2183 int nid;
2184 nid = OBJ_txt2nid(const_cast<char *>(oidname));
2185 if (nid == NID_undef) {
2186 tqslTrace("tqsl_add_bag_attribute", "OBJ_txt2nid err %s", tqsl_openssl_error());
2187 return 1;
2188 }
2189 unsigned char *uni;
2190 int unilen;
2191 if (asc2uni(value.c_str(), value.length(), &uni, &unilen)) {
2192 ASN1_TYPE *val;
2193 X509_ATTRIBUTE *attrib;
2194 if (!uni[unilen - 1] && !uni[unilen - 2])
2195 unilen -= 2;
2196 if ((val = ASN1_TYPE_new()) != 0) {
2197 ASN1_TYPE_set(val, V_ASN1_BMPSTRING, uni);
2198 if ((attrib = X509_ATTRIBUTE_new()) != 0) {
2199 X509_ATTRIBUTE_set1_object(attrib, OBJ_nid2obj(nid));
2200 if ((X509_ATTRIBUTE_set1_data(attrib, V_ASN1_BMPSTRING, uni, unilen)) != 0) {
2201 #if (OPENSSL_VERSION_NUMBER & 0xfffff000) == 0x00906000
2202 attrib->set = 1;
2203 #else
2204 #if OPENSSL_VERSION_NUMBER < 0x10100000L || defined(LIBRESSL_VERSION_NUMBER)
2205 #if (OPENSSL_VERSION_NUMBER & 0xfffff000) >= 0x00907000 || defined(LIBRESSL_VERSION_NUMBER)
2206 attrib->single = 0;
2207 #else
2208 #error "Unexpected OpenSSL version; check X509_ATTRIBUTE struct compatibility"
2209 #endif
2210 #endif
2211 #endif
2212 #if OPENSSL_VERSION_NUMBER >= 0x10100000L && !defined(LIBRESSL_VERSION_NUMBER)
2213 STACK_OF(X509_ATTRIBUTE) *sk;
2214 sk = (STACK_OF(X509_ATTRIBUTE)*)PKCS12_SAFEBAG_get0_attrs(bag);
2215 if (sk) {
2216 sk_X509_ATTRIBUTE_push(sk, attrib);
2217 #else
2218 if (bag->attrib) {
2219 sk_X509_ATTRIBUTE_push(bag->attrib, attrib);
2220 #endif
2221 //cerr << "Added " << oidname << endl;
2222 } else {
2223 tqslTrace("tqsl_add_bag_attribute", "no attrib");
2224 return 1;
2225 }
2226 } else {
2227 tqslTrace("tqsl_add_bag_attribute", "no value set");
2228 return 1;
2229 }
2230 } else {
2231 tqslTrace("tqsl_add_bag_attribute", "attrib create err %s", tqsl_openssl_error());
2232 return 1;
2233 }
2234 } else {
2235 tqslTrace("tqsl_add_bag_attribute", "bmp->data empty");
2236 return 1;
2237 }
2238 } else { // asc2uni ok
2239 tqslTrace("tqsl_add_bag_attribute", "asc2uni err %s", tqsl_openssl_error());
2240 return 1;
2241 }
2242 return 0;
2243 }
2244
2245 static int
2246 tqsl_exportPKCS12(tQSL_Cert cert, bool returnB64, const char *filename, char *base64, int b64len, const char *p12password) {
2247 STACK_OF(X509) *root_sk = 0, *ca_sk = 0, *chain = 0;
2248 const char *cp;
2249 char rootpath[256], capath[256];
2250 char buf[256];
2251 unsigned char keyid[EVP_MAX_MD_SIZE];
2252 unsigned int keyidlen = 0;
2253 STACK_OF(PKCS12_SAFEBAG) *bags = 0;
2254 PKCS12_SAFEBAG *bag = 0;
2255 STACK_OF(PKCS7) *safes = 0;
2256 PKCS7 *authsafe = 0;
2257 int cert_pbe = NID_pbe_WithSHA1And40BitRC2_CBC;
2258 int key_pbe = NID_pbe_WithSHA1And3_Key_TripleDES_CBC;
2259 PKCS8_PRIV_KEY_INFO *p8 = 0;
2260 PKCS12 *p12 = 0;
2261 BIO *out = 0, *b64 = 0;
2262 string callSign, issuerOrganization, issuerOrganizationalUnit;
2263 tQSL_Date date;
2264 string QSONotBeforeDate, QSONotAfterDate, dxccEntity, Email,
2265 Address1, Address2, City, State, Postal, Country;
2266 int dxcc = 0;
2267 int rval = 1;
2268
2269 tqslTrace("tqsl_exportPKCS12", NULL);
2270 if (cert == NULL || !tqsl_cert_check(TQSL_API_TO_CERT(cert), false)) {
2271 tqslTrace("tqsl_exportPKCS12", "arg error cert=0x%lx", cert);
2272 tQSL_Error = TQSL_ARGUMENT_ERROR;
2273 return 1;
2274 }
2275 if ((returnB64 && base64 == NULL) || (!returnB64 && filename == NULL)) {
2276 tqslTrace("tqsl_exportPKCS12", "arg error returnB64=%d base64=0x%lx filename=0x%lx", returnB64, base64, filename);
2277 tQSL_Error = TQSL_ARGUMENT_ERROR;
2278 return 1;
2279 }
2280
2281 /* Get parameters for key bag attributes */
2282 if (tqsl_getCertificateCallSign(cert, buf, sizeof buf)) {
2283 tqslTrace("tqsl_exportPKCS12", "get callsign err %d", tQSL_Error);
2284 return 1;
2285 }
2286 callSign = buf;
2287 if (tqsl_getCertificateIssuerOrganization(cert, buf, sizeof buf)) {
2288 tqslTrace("tqsl_exportPKCS12", "get org err %d", tQSL_Error);
2289 return 1;
2290 }
2291 issuerOrganization = buf;
2292 if (tqsl_getCertificateIssuerOrganizationalUnit(cert, buf, sizeof buf)) {
2293 tqslTrace("tqsl_exportPKCS12", "get ou err %d", tQSL_Error);
2294 return 1;
2295 }
2296 issuerOrganizationalUnit = buf;
2297 if (!TQSL_API_TO_CERT(cert)->keyonly) {
2298 if (tqsl_getCertificateEmailAddress(cert, buf, sizeof buf)) {
2299 tqslTrace("tqsl_exportPKCS12", "get email err %d", tQSL_Error);
2300 return 1;
2301 }
2302 Email = buf;
2303 if (tqsl_getCertificateRequestAddress1(cert, buf, sizeof buf)) {
2304 tqslTrace("tqsl_exportPKCS12", "get addr1 err %d", tQSL_Error);
2305 return 1;
2306 }
2307 Address1 = buf;
2308 if (tqsl_getCertificateRequestAddress2(cert, buf, sizeof buf)) {
2309 tqslTrace("tqsl_exportPKCS12", "get addr2 err %d", tQSL_Error);
2310 return 1;
2311 }
2312 Address2 = buf;
2313 if (tqsl_getCertificateRequestCity(cert, buf, sizeof buf)) {
2314 tqslTrace("tqsl_exportPKCS12", "get city err %d", tQSL_Error);
2315 return 1;
2316 }
2317 City = buf;
2318 if (tqsl_getCertificateRequestState(cert, buf, sizeof buf)) {
2319 tqslTrace("tqsl_exportPKCS12", "get state err %d", tQSL_Error);
2320 return 1;
2321 }
2322 State = buf;
2323 if (tqsl_getCertificateRequestPostalCode(cert, buf, sizeof buf)) {
2324 tqslTrace("tqsl_exportPKCS12", "get postal err %d", tQSL_Error);
2325 return 1;
2326 }
2327 Postal = buf;
2328 if (tqsl_getCertificateRequestCountry(cert, buf, sizeof buf)) {
2329 tqslTrace("tqsl_exportPKCS12", "get country err %d", tQSL_Error);
2330 return 1;
2331 }
2332 Country = buf;
2333 }
2334 if (tqsl_getCertificateQSONotBeforeDate(cert, &date)) {
2335 tqslTrace("tqsl_exportPKCS12", "get qso not before err %d", tQSL_Error);
2336 return 1;
2337 }
2338 if (!tqsl_convertDateToText(&date, buf, sizeof buf)) {
2339 tqslTrace("tqsl_exportPKCS12", "qso not before err %d", tQSL_Error);
2340 return 1;
2341 }
2342 QSONotBeforeDate = buf;
2343 if (tqsl_getCertificateQSONotAfterDate(cert, &date)) {
2344 tqslTrace("tqsl_exportPKCS12", "get qso not after err %d", tQSL_Error);
2345 return 1;
2346 }
2347 if (!tqsl_isDateNull(&date)) {
2348 if (!tqsl_convertDateToText(&date, buf, sizeof buf)) {
2349 tqslTrace("tqsl_exportPKCS12", "qso not before err %d", tQSL_Error);
2350 return 1;
2351 }
2352 QSONotAfterDate = buf;
2353 }
2354 if (tqsl_getCertificateDXCCEntity(cert, &dxcc)) {
2355 tqslTrace("tqsl_exportPKCS12", "get entity err %d", tQSL_Error);
2356 return 1;
2357 }
2358 snprintf(buf, sizeof buf, "%d", dxcc);
2359 dxccEntity = buf;
2360
2361 if (TQSL_API_TO_CERT(cert)->key == NULL) {
2362 tqslTrace("tqsl_exportPKCS12", "key is null");
2363 tQSL_Error = TQSL_SIGNINIT_ERROR;
2364 return 1;
2365 }
2366
2367 if (!TQSL_API_TO_CERT(cert)->keyonly) {
2368 tqslTrace("tqsl_exportPKCS12", "keyonly cert");
2369 /* Generate local key ID to tie key to cert */
2370 X509_digest(TQSL_API_TO_CERT(cert)->cert, EVP_sha1(), keyid, &keyidlen);
2371
2372 /* Check the chain of authority back to a trusted root */
2373 tqsl_make_cert_path("root", rootpath, sizeof rootpath);
2374 if ((root_sk = tqsl_ssl_load_certs_from_file(rootpath)) == NULL) {
2375 if (!tqsl_ssl_error_is_nofile()) {
2376 tqslTrace("tqsl_exportPKCS12", "can't find certs");
2377 goto p12_end;
2378 }
2379 }
2380 tqsl_make_cert_path("authorities", capath, sizeof capath);
2381 if ((ca_sk = tqsl_ssl_load_certs_from_file(capath)) == NULL) {
2382 if (!tqsl_ssl_error_is_nofile()) {
2383 tqslTrace("tqsl_exportPKCS12", "can't find certs");
2384 goto p12_end;
2385 }
2386 }
2387
2388 /* tqsl_ssl_verify_cert will collect the certificates in the chain, back to the
2389 * root certificate, verify them and return a stack containing copies of just
2390 * those certificates (including the user certificate).
2391 */
2392
2393 cp = tqsl_ssl_verify_cert(TQSL_API_TO_CERT(cert)->cert, ca_sk, root_sk, 0, &tqsl_expired_is_ok, &chain);
2394 if (cp) {
2395 if (chain)
2396 sk_X509_free(chain);
2397 tQSL_Error = TQSL_CUSTOM_ERROR;
2398 strncpy(tQSL_CustomError, cp, sizeof tQSL_CustomError);
2399 tqslTrace("tqsl_exportPKCS12", "verify fail: %s", cp);
2400 return 1;
2401 }
2402 } // !keyonly
2403
2404 tQSL_Error = TQSL_OPENSSL_ERROR; // Assume error
2405
2406 /* Open the output file */
2407 if (!returnB64) {
2408 out = BIO_new_file(filename, "wb");
2409 } else {
2410 b64 = BIO_new(BIO_f_base64());
2411 out = BIO_new(BIO_s_mem());
2412 out = BIO_push(b64, out);
2413 }
2414 if (!out) {
2415 tqslTrace("tqsl_exportPKCS12", "BIO_new err %s", tqsl_openssl_error());
2416 goto p12_end;
2417 }
2418
2419 safes = sk_PKCS7_new_null();
2420
2421 if (!TQSL_API_TO_CERT(cert)->keyonly) {
2422 /* Create a safebag stack and fill it with the needed certs */
2423 bags = sk_PKCS12_SAFEBAG_new_null();
2424 for (int i = 0; i < sk_X509_num(chain); i++) {
2425 X509 *x = sk_X509_value(chain, i);
2426 #if (OPENSSL_VERSION_NUMBER & 0xfffff000) == 0x00906000
2427 bag = PKCS12_pack_safebag(reinterpret_cast<char *>(x), (int (*)())i2d_X509, NID_x509Certificate, NID_certBag);
2428 #else
2429 bag = PKCS12_x5092certbag(x);
2430 #endif
2431 if (!bag) {
2432 tqslTrace("tqsl_exportPKCS12", "Error creating bag: %s", tqsl_openssl_error());
2433 goto p12_end;
2434 }
2435 if (x == TQSL_API_TO_CERT(cert)->cert) {
2436 PKCS12_add_friendlyname(bag, "TrustedQSL user certificate", -1);
2437 PKCS12_add_localkeyid(bag, keyid, keyidlen);
2438 }
2439 sk_PKCS12_SAFEBAG_push(bags, bag);
2440 }
2441
2442 /* Convert stack of safebags into an authsafe */
2443 authsafe = PKCS12_pack_p7encdata(cert_pbe, p12password, -1, 0, 0, PKCS12_DEFAULT_ITER, bags);
2444 if (!authsafe) {
2445 tqslTrace("tqsl_exportPKCS12", "Error creating authsafe: %s", tqsl_openssl_error());
2446 goto p12_end;
2447 }
2448 sk_PKCS12_SAFEBAG_pop_free(bags, PKCS12_SAFEBAG_free);
2449 bags = 0;
2450
2451 /* Add to stack of authsafes */
2452 sk_PKCS7_push(safes, authsafe);
2453 } // !keyonly
2454
2455 /* Make a shrouded key bag */
2456 p8 = EVP_PKEY2PKCS8(TQSL_API_TO_CERT(cert)->key);
2457 if (!p8) {
2458 tqslTrace("tqsl_exportPKCS12", "Error creating p8 container: %s", tqsl_openssl_error());
2459 goto p12_end;
2460 }
2461 bag = PKCS12_MAKE_SHKEYBAG(key_pbe, p12password, -1, 0, 0, PKCS12_DEFAULT_ITER, p8);
2462 if (!bag) {
2463 tqslTrace("tqsl_exportPKCS12", "Error creating p8 keybag: %s", tqsl_openssl_error());
2464 goto p12_end;
2465 }
2466 PKCS8_PRIV_KEY_INFO_free(p8);
2467 p8 = NULL;
2468 PKCS12_add_friendlyname(bag, "TrustedQSL user certificate", -1);
2469 if (!TQSL_API_TO_CERT(cert)->keyonly)
2470 PKCS12_add_localkeyid(bag, keyid, keyidlen);
2471
2472 /* Add the attributes to the private key bag */
2473 tqsl_add_bag_attribute(bag, "AROcallsign", callSign);
2474 tqsl_add_bag_attribute(bag, "QSONotBeforeDate", QSONotBeforeDate);
2475 if (QSONotAfterDate != "")
2476 tqsl_add_bag_attribute(bag, "QSONotAfterDate", QSONotAfterDate);
2477 tqsl_add_bag_attribute(bag, "tqslCRQIssuerOrganization", issuerOrganization);
2478 tqsl_add_bag_attribute(bag, "tqslCRQIssuerOrganizationalUnit", issuerOrganizationalUnit);
2479 tqsl_add_bag_attribute(bag, "dxccEntity", dxccEntity);
2480 tqsl_add_bag_attribute(bag, "tqslCRQEmail", Email);
2481 tqsl_add_bag_attribute(bag, "tqslCRQAddress1", Address1);
2482 tqsl_add_bag_attribute(bag, "tqslCRQAddress2", Address2);
2483 tqsl_add_bag_attribute(bag, "tqslCRQCity", City);
2484 tqsl_add_bag_attribute(bag, "tqslCRQState", State);
2485 tqsl_add_bag_attribute(bag, "tqslCRQPostal", Postal);
2486 tqsl_add_bag_attribute(bag, "tqslCRQCountry", Country);
2487
2488 bags = sk_PKCS12_SAFEBAG_new_null();
2489 if (!bags) {
2490 tqslTrace("tqsl_exportPKCS12", "Error creating safebag: %s", tqsl_openssl_error());
2491 goto p12_end;
2492 }
2493 sk_PKCS12_SAFEBAG_push(bags, bag);
2494
2495 /* Turn shrouded key bag into unencrypted safe bag and add to safes stack */
2496 authsafe = PKCS12_pack_p7data(bags);
2497 sk_PKCS12_SAFEBAG_pop_free(bags, PKCS12_SAFEBAG_free);
2498 bags = NULL;
2499 sk_PKCS7_push(safes, authsafe);
2500
2501 /* Form into PKCS12 data */
2502 p12 = PKCS12_init(NID_pkcs7_data);
2503 M_PKCS12_pack_authsafes(p12, safes);
2504
2505 sk_PKCS7_pop_free(safes, PKCS7_free);
2506 safes = NULL;
2507 PKCS12_set_mac(p12, p12password, -1, 0, 0, PKCS12_DEFAULT_ITER, 0);
2508
2509 /* Write the PKCS12 data */
2510
2511 i2d_PKCS12_bio(out, p12);
2512 if (BIO_flush(out) != 1) {
2513 rval = 1;
2514 tqslTrace("tqsl_exportPKCS12", "Error writing pkcs12: %s", tqsl_openssl_error());
2515 goto p12_end;
2516 }
2517
2518 if (returnB64) {
2519 char *encoded;
2520 int len;
2521 len = BIO_get_mem_data(out, &encoded);
2522 encoded[len - 1] = '\0';
2523 strncpy(base64, encoded, b64len);
2524 }
2525
2526 rval = 0;
2527 tQSL_Error = TQSL_NO_ERROR;
2528 p12_end:
2529 if (out) {
2530 BIO_free(out);
2531 if (rval && !returnB64) {
2532 #ifdef _WIN32
2533 wchar_t* wfilename = utf8_to_wchar(filename);
2534 _wunlink(wfilename);
2535 free_wchar(wfilename);
2536 #else
2537 unlink(filename);
2538 #endif
2539 }
2540 }
2541 if (chain)
2542 sk_X509_free(chain);
2543 if (root_sk)
2544 sk_X509_free(root_sk);
2545 if (ca_sk)
2546 sk_X509_free(ca_sk);
2547 if (bags)
2548 sk_PKCS12_SAFEBAG_pop_free(bags, PKCS12_SAFEBAG_free);
2549 if (safes)
2550 sk_PKCS7_pop_free(safes, PKCS7_free);
2551 if (p8)
2552 PKCS8_PRIV_KEY_INFO_free(p8);
2553 return rval;
2554 }
2555
2556 DLLEXPORT int CALLCONVENTION
2557 tqsl_exportPKCS12File(tQSL_Cert cert, const char *filename, const char *p12password) {
2558 tqslTrace("tqsl_exportPKCS12File", NULL);
2559 return tqsl_exportPKCS12(cert, false, filename, NULL, 0, p12password);
2560 }
2561
2562 DLLEXPORT int CALLCONVENTION
2563 tqsl_exportPKCS12Base64(tQSL_Cert cert, char *base64, int b64len, const char *p12password) {
2564 tqslTrace("tqsl_exportPKCS12Base64", NULL);
2565 return tqsl_exportPKCS12(cert, true, NULL, base64, b64len, p12password);
2566 }
2567
2568 static string
2569 tqsl_asn1_octet_string_to_hex(ASN1_OCTET_STRING *os) {
2570 string str;
2571
2572 for (int k = 0; k < os->length; k++) {
2573 char hex[3] = " ";
2574 hex[0] = ((os->data[k] >> 4) & 0xf) + '0';
2575 if (hex[0] > '9') hex[0] += 'A' - '9' - 1;
2576 hex[1] = (os->data[k] & 0xf) + '0';
2577 if (hex[1] > '9') hex[1] += 'A' - '9' - 1;
2578 if (str.size()) str += " ";
2579 str += hex;
2580 }
2581 return str;
2582 }
2583
2584 struct tqsl_imported_cert {
2585 string pem;
2586 string keyid;
2587 string callsign;
2588 };
2589
2590 static int
2591 tqsl_get_bag_attribute(PKCS12_SAFEBAG *bag, const char *oidname, string& str) {
2592 const ASN1_TYPE *attr;
2593
2594 str = "";
2595 if ((attr = PKCS12_get_attr(bag, OBJ_txt2nid(const_cast<char *>(oidname)))) != 0) {
2596 if (attr->type != V_ASN1_BMPSTRING) {
2597 tQSL_Error = TQSL_CERT_TYPE_ERROR;
2598 tqslTrace("tqsl_get_bag_attribute", "cert type error oid %s", oidname);
2599 return 1;
2600 }
2601 char *c = uni2asc(attr->value.bmpstring->data, attr->value.bmpstring->length);
2602 str = c;
2603 OPENSSL_free(c);
2604 }
2605 return 0;
2606 }
2607
2608 static int
2609 tqsl_importPKCS12(bool importB64, const char *filename, const char *base64, const char *p12password, const char *password,
2610 int (*pwcb)(char *, int, void *), int(*cb)(int, const char *, void *), void *userdata) {
2611 PKCS12 *p12 = 0;
2612 PKCS12_SAFEBAG *bag;
2613 PKCS8_PRIV_KEY_INFO *p8 = 0;
2614 EVP_PKEY *pkey = 0;
2615 BIO *in = 0, *bio = 0 , *b64 = 0;
2616 STACK_OF(PKCS7) *safes = 0;
2617 STACK_OF(PKCS12_SAFEBAG) *bags = 0;
2618 PKCS7 *p7;
2619 X509 *x;
2620 BASIC_CONSTRAINTS *bs = 0;
2621 ASN1_OBJECT *callobj = 0, *obj = 0;
2622 const ASN1_TYPE *attr = 0;
2623 const EVP_CIPHER *cipher;
2624 unsigned char *cp;
2625 int i, j, bagnid, len;
2626 vector<tqsl_imported_cert> rootcerts;
2627 vector<tqsl_imported_cert> cacerts;
2628 vector<tqsl_imported_cert> usercerts;
2629 vector<tqsl_imported_cert> *certlist;
2630 vector<tqsl_imported_cert>::iterator it;
2631 bool is_cacert;
2632 string public_key, private_key, private_keyid, key_callsign, str;
2633 map<string, string> key_attr;
2634 map<string, string> newrecord;
2635 map<string, string>::iterator mit;
2636 char path[256], pw[256];
2637 int rval = 1;
2638
2639 tqslTrace("tqsl_importPKCS12", NULL);
2640
2641 if (tqsl_init())
2642 return 1;
2643 if ((!importB64 && filename == NULL) || (importB64 && base64 == NULL)) {
2644 tqslTrace("tqsl_importPKCS12", "arg error importB64=%d filename=0x%lx base64=0x%lx", importB64, filename, base64);
2645 tQSL_Error = TQSL_ARGUMENT_ERROR;
2646 return 1;
2647 }
2648
2649 tQSL_ImportCall[0] = '\0';
2650 tQSL_ImportSerial = 0;
2651 ImportCall[0] = '\0';
2652 tQSL_Error = TQSL_OPENSSL_ERROR;
2653
2654 /* Read in the PKCS#12 file */
2655 if (importB64) {
2656 b64 = BIO_new(BIO_f_base64());
2657 in = BIO_new_mem_buf(const_cast<char *>(base64), strlen(base64));
2658 in = BIO_push(b64, in);
2659 } else {
2660 in = BIO_new_file(filename, "rb");
2661 }
2662 if (in == 0) {
2663 tqslTrace("tqsl_importPKCS12", "Couldn't create bio: %s", tqsl_openssl_error());
2664 goto imp_end;
2665 }
2666 if ((p12 = d2i_PKCS12_bio(in, 0)) == 0) {
2667 tqslTrace("tqsl_importPKCS12", "Couldn't read pkcs12: %s", tqsl_openssl_error());
2668 goto imp_end;
2669 }
2670 BIO_free(in);
2671 in = 0;
2672
2673 /* Verify MAC */
2674 if (!PKCS12_verify_mac(p12, p12password, -1)) {
2675 tqslTrace("tqsl_importPKCS12", "Mac doesn't verify");
2676 tQSL_Error = TQSL_PASSWORD_ERROR;
2677 goto imp_end;
2678 }
2679 /* Loop through the authsafes */
2680 if ((safes = M_PKCS12_unpack_authsafes(p12)) == 0) {
2681 tqslTrace("tqsl_importPKCS12", "Can't unpack authsafe: %s", tqsl_openssl_error());
2682 goto imp_end;
2683 }
2684 callobj = OBJ_txt2obj("AROcallsign", 0);
2685 for (i = 0; i < sk_PKCS7_num(safes); i++) {
2686 tqsl_imported_cert imported_cert;
2687 p7 = sk_PKCS7_value(safes, i);
2688 bagnid = OBJ_obj2nid(p7->type);
2689 if (bagnid == NID_pkcs7_data) {
2690 bags = PKCS12_unpack_p7data(p7);
2691 } else if (bagnid == NID_pkcs7_encrypted) {
2692 bags = PKCS12_unpack_p7encdata(p7, p12password, strlen(p12password));
2693 } else {
2694 continue; // Not something we understand
2695 }
2696 if (!bags) {
2697 tQSL_Error = TQSL_PKCS12_ERROR;
2698 tqslTrace("tqsl_importPKCS12", "bags empty: %s", tqsl_openssl_error());
2699 goto imp_end;
2700 }
2701 /* Loop through safebags */
2702 for (j = 0; j < sk_PKCS12_SAFEBAG_num(bags); j++) {
2703 tqsl_imported_cert imported_cert;
2704 bag = sk_PKCS12_SAFEBAG_value(bags, j);
2705 switch (M_PKCS12_bag_type(bag)) {
2706 case NID_certBag:
2707 if (M_PKCS12_cert_bag_type(bag) != NID_x509Certificate)
2708 break; // Can't handle anything else
2709 if ((x = M_PKCS12_certbag2x509(bag)) == 0) {
2710 tqslTrace("tqsl_importPKCS12", "bag2x509: %s", tqsl_openssl_error());
2711 goto imp_end;
2712 }
2713 if ((bio = BIO_new(BIO_s_mem())) == NULL) {
2714 tqslTrace("tqsl_importPKCS12", "bio_new: %s", tqsl_openssl_error());
2715 goto imp_end;
2716 }
2717 if (!PEM_write_bio_X509(bio, x)) {
2718 tqslTrace("tqsl_importPKCS12", "write_bio: %s", tqsl_openssl_error());
2719 goto imp_end;
2720 }
2721 len = static_cast<int>(BIO_get_mem_data(bio, &cp));
2722 imported_cert.pem = string((const char *)cp, len);
2723 if ((attr = PKCS12_get_attr(bag, NID_localKeyID)) != 0) {
2724 if (attr->type != V_ASN1_OCTET_STRING) {
2725 tqslTrace("tqsl_importPKCS12", "Cert type mismatch");
2726 tQSL_Error = TQSL_CERT_TYPE_ERROR;
2727 goto imp_end;
2728 }
2729 imported_cert.keyid = tqsl_asn1_octet_string_to_hex(attr->value.octet_string);
2730 }
2731 BIO_free(bio);
2732 bio = 0;
2733 is_cacert = false;
2734 if ((bs = reinterpret_cast<BASIC_CONSTRAINTS *>(X509_get_ext_d2i(x, NID_basic_constraints, 0, 0))) != 0) {
2735 if (bs->ca)
2736 is_cacert = true;
2737 BASIC_CONSTRAINTS_free(bs);
2738 bs = 0;
2739 }
2740 certlist = &usercerts;
2741 if (is_cacert) {
2742 if (X509_check_issued(x, x) == X509_V_OK) // Self signed must be trusted
2743 certlist = &rootcerts;
2744 else
2745 certlist = &cacerts;
2746 } else {
2747 /* Make sure the cert is TQSL compatible */
2748 TQSL_X509_NAME_ITEM item;
2749 char nbuf[40];
2750 char callbuf[256];
2751 item.name_buf = nbuf;
2752 item.name_buf_size = sizeof nbuf;
2753 item.value_buf = callbuf;
2754 item.value_buf_size = sizeof callbuf;
2755 if (!tqsl_cert_get_subject_name_entry(x, "AROcallsign", &item)) {
2756 tqslTrace("tqsl_importPKCS12", "Cert type mismatch");
2757 tQSL_Error = TQSL_CERT_TYPE_ERROR;
2758 goto imp_end;
2759 }
2760 imported_cert.callsign = callbuf;
2761 }
2762 (*certlist).push_back(imported_cert);
2763 break;
2764 case NID_pkcs8ShroudedKeyBag:
2765 if ((attr = PKCS12_get_attr(bag, NID_localKeyID)) != 0) {
2766 if (attr->type != V_ASN1_OCTET_STRING) {
2767 tQSL_Error = TQSL_CERT_TYPE_ERROR;
2768 tqslTrace("tqsl_importPKCS12", "Cert type mismatch");
2769 goto imp_end;
2770 }
2771 private_keyid = tqsl_asn1_octet_string_to_hex(attr->value.octet_string);
2772 }
2773 if (tqsl_get_bag_attribute(bag, "AROcallsign", key_callsign)) {
2774 tqslTrace("tqsl_importPKCS12", "Cert type mismatch - no callsign");
2775 goto imp_end;
2776 }
2777 if (tqsl_get_bag_attribute(bag, "dxccEntity", str)) {
2778 tqslTrace("tqsl_importPKCS12", "Cert type mismatch - no dxcc");
2779 goto imp_end;
2780 }
2781 if (str != "")
2782 key_attr["TQSL_CRQ_DXCC_ENTITY"] = str;
2783 if (tqsl_get_bag_attribute(bag, "QSONotBeforeDate", str)) {
2784 tqslTrace("tqsl_importPKCS12", "Cert type mismatch - no qsonotbefore");
2785 goto imp_end;
2786 }
2787 if (str != "")
2788 key_attr["TQSL_CRQ_QSO_NOT_BEFORE"] = str;
2789 if (tqsl_get_bag_attribute(bag, "QSONotAfterDate", str)) {
2790 tqslTrace("tqsl_importPKCS12", "Cert type mismatch - no qsonotafter");
2791 goto imp_end;
2792 }
2793 if (str != "")
2794 key_attr["TQSL_CRQ_QSO_NOT_AFTER"] = str;
2795 if (tqsl_get_bag_attribute(bag, "tqslCRQIssuerOrganization", str)) {
2796 tqslTrace("tqsl_importPKCS12", "Cert type mismatch - no org");
2797 goto imp_end;
2798 }
2799 if (str != "")
2800 key_attr["TQSL_CRQ_PROVIDER"] = str;
2801 if (tqsl_get_bag_attribute(bag, "tqslCRQIssuerOrganizationalUnit", str)) {
2802 tqslTrace("tqsl_importPKCS12", "Cert type mismatch - no ou");
2803 goto imp_end;
2804 }
2805 if (str != "")
2806 key_attr["TQSL_CRQ_PROVIDER_UNIT"] = str;
2807 if (tqsl_get_bag_attribute(bag, "tqslCRQEmail", str)) {
2808 tqslTrace("tqsl_importPKCS12", "Cert type mismatch - no email");
2809 goto imp_end;
2810 }
2811 if (str != "")
2812 key_attr["TQSL_CRQ_EMAIL"] = str;
2813 if (tqsl_get_bag_attribute(bag, "tqslCRQAddress1", str)) {
2814 tqslTrace("tqsl_importPKCS12", "Cert type mismatch - no addr1");
2815 goto imp_end;
2816 }
2817 if (str != "")
2818 key_attr["TQSL_CRQ_ADDRESS1"] = str;
2819 if (tqsl_get_bag_attribute(bag, "tqslCRQAddress2", str)) {
2820 tqslTrace("tqsl_importPKCS12", "Cert type mismatch - no addr2");
2821 goto imp_end;
2822 }
2823 if (str != "")
2824 key_attr["TQSL_CRQ_ADDRESS2"] = str;
2825 if (tqsl_get_bag_attribute(bag, "tqslCRQCity", str)) {
2826 tqslTrace("tqsl_importPKCS12", "Cert type mismatch - no city");
2827 goto imp_end;
2828 }
2829 if (str != "")
2830 key_attr["TQSL_CRQ_CITY"] = str;
2831 if (tqsl_get_bag_attribute(bag, "tqslCRQState", str)) {
2832 tqslTrace("tqsl_importPKCS12", "Cert type mismatch - no state");
2833 goto imp_end;
2834 }
2835 if (str != "")
2836 key_attr["TQSL_CRQ_STATE"] = str;
2837 if (tqsl_get_bag_attribute(bag, "tqslCRQPostal", str)) {
2838 tqslTrace("tqsl_importPKCS12", "Cert type mismatch - no postal");
2839 goto imp_end;
2840 }
2841 if (str != "")
2842 key_attr["TQSL_CRQ_POSTAL"] = str;
2843 if (tqsl_get_bag_attribute(bag, "tqslCRQCountry", str)) {
2844 tqslTrace("tqsl_importPKCS12", "Cert type mismatch - no country");
2845 goto imp_end;
2846 }
2847 if (str != "")
2848 key_attr["TQSL_CRQ_COUNTRY"] = str;
2849 if ((p8 = M_PKCS12_decrypt_skey(bag, p12password, strlen(p12password))) == 0) {
2850 tqslTrace("tqsl_importPKCS12", "password error");
2851 goto imp_end;
2852 }
2853 if ((pkey = EVP_PKCS82PKEY(p8)) == 0) {
2854 tqslTrace("tqsl_importPKCS12", "pkey error");
2855 goto imp_end;
2856 }
2857 if ((bio = BIO_new(BIO_s_mem())) == NULL) {
2858 tqslTrace("tqsl_importPKCS12", "bio_new error %s", tqsl_openssl_error());
2859 goto imp_end;
2860 }
2861 if (password == 0) {
2862 if (pwcb) {
2863 if ((*pwcb)(pw, sizeof pw -1, userdata)) {
2864 tqslTrace("tqsl_importPKCS12", "operator aborted at password prompt");
2865 tQSL_Error = TQSL_OPERATOR_ABORT;
2866 goto imp_end;
2867 }
2868 password = pw;
2869 } else {
2870 password = NULL;
2871 }
2872 }
2873 if (password && *password != '\0') {
2874 cipher = EVP_des_ede3_cbc();
2875 len = strlen(password);
2876 } else {
2877 cipher = 0;
2878 len = 0;
2879 }
2880 if (!PEM_write_bio_PrivateKey(bio, pkey, cipher, (unsigned char *)password, len, 0, 0)) {
2881 tqslTrace("tqsl_importPKCS12", "writing bio err: %s", tqsl_openssl_error());
2882 goto imp_end;
2883 }
2884 len = static_cast<int>(BIO_get_mem_data(bio, &cp));
2885 private_key = string((const char *)cp, len);
2886 BIO_free(bio);
2887 if ((bio = BIO_new(BIO_s_mem())) == NULL) {
2888 tqslTrace("tqsl_importPKCS12", "new bio err: %s", tqsl_openssl_error());
2889 goto imp_end;
2890 }
2891 if (!PEM_write_bio_PUBKEY(bio, pkey)) {
2892 tqslTrace("tqsl_importPKCS12", "write pubkey bio err: %s", tqsl_openssl_error());
2893 goto imp_end;
2894 }
2895 len = static_cast<int>(BIO_get_mem_data(bio, &cp));
2896 public_key = string((const char *)cp, len);
2897 BIO_free(bio);
2898 bio = 0;
2899 EVP_PKEY_free(pkey);
2900 pkey = 0;
2901 PKCS8_PRIV_KEY_INFO_free(p8);
2902 p8 = 0;
2903 break;
2904 case NID_keyBag:
2905 tqslTrace("tqsl_importPKCS12", "cert type err: NID_keyBag");
2906 tQSL_Error = TQSL_CERT_TYPE_ERROR;
2907 goto imp_end;
2908 } // bag type switch
2909 } // safebags loop
2910 sk_PKCS12_SAFEBAG_pop_free(bags, PKCS12_SAFEBAG_free);
2911 bags = 0;
2912 }
2913 sk_PKCS7_pop_free(safes, PKCS7_free);
2914 safes = 0;
2915
2916 /* Now we have the certificates and key pair, so add them to the local store */
2917
2918 tqslTrace("tqsl_importPKCS12", "have keys");
2919 if (key_callsign == "") {
2920 /* Need to get call sign from cert. The tQSL_exportKeys function puts the
2921 * call sign in a safebag attribute that should have been read already,
2922 * but if some other software created the PKCS#12 file that may not have
2923 * happened. There should, however, be a localKeyID attribute that matches
2924 * the key to the certificate. If not, it's an error.
2925 */
2926 if (private_keyid == "") { // No key ID, can't find cert
2927 tqslTrace("tqsl_importPKCS12", "no callsign attribute");
2928 tQSL_Error = TQSL_CERT_TYPE_ERROR;
2929 goto imp_end;
2930 }
2931 for (it = usercerts.begin(); it != usercerts.end(); it++) {
2932 if ((*it).keyid == private_keyid) {
2933 key_callsign = (*it).callsign;
2934 break;
2935 }
2936 }
2937 if (key_callsign == "") { // Can't find cert or callsign
2938 tqslTrace("tqsl_importPKCS12", "can't find cert or callsign");
2939 tQSL_Error = TQSL_CERT_TYPE_ERROR;
2940 goto imp_end;
2941 }
2942 }
2943
2944 if (!tqsl_make_key_path(key_callsign.c_str(), path, sizeof path)) {
2945 tqslTrace("tqsl_importPKCS12", "keypath error %d", tQSL_Error);
2946 goto imp_end;
2947 }
2948 newrecord["PUBLIC_KEY"] = public_key;
2949 newrecord["PRIVATE_KEY"] = private_key;
2950 newrecord["CALLSIGN"] = key_callsign;
2951 for (mit = key_attr.begin(); mit != key_attr.end(); mit++)
2952 newrecord[mit->first] = mit->second;
2953
2954 if (tqsl_replace_key(key_callsign.c_str(), path, newrecord, cb, userdata)) {
2955 tqslTrace("tqsl_importPKCS12", "replace key error %d", tQSL_Error);
2956 goto imp_end;
2957 }
2958 for (it = rootcerts.begin(); it != rootcerts.end(); it++) {
2959 if (tqsl_import_cert(it->pem.c_str(), tqsllib::ROOTCERT, cb, userdata) && tQSL_Error != TQSL_CERT_ERROR) {
2960 tqslTrace("tqsl_importPKCS12", "import root cert error %d", tQSL_Error);
2961 goto imp_end;
2962 }
2963 }
2964 for (it = cacerts.begin(); it != cacerts.end(); it++) {
2965 if (tqsl_import_cert(it->pem.c_str(), tqsllib::CACERT, cb, userdata) && tQSL_Error != TQSL_CERT_ERROR) {
2966 tqslTrace("tqsl_importPKCS12", "import ca cert error %d", tQSL_Error);
2967 goto imp_end;
2968 }
2969 }
2970 rval = 0; // Assume no errors
2971 for (it = usercerts.begin(); it != usercerts.end(); it++) {
2972 if (tqsl_import_cert(it->pem.c_str(), tqsllib::USERCERT, cb, userdata)) {
2973 if (tQSL_Error == TQSL_CERT_ERROR) {
2974 rval = 1; // Remember failure to import
2975 continue;
2976 }
2977 char savepath[1024], badpath[1024];
2978 strncpy(badpath, path, sizeof(badpath));
2979 strncat(badpath, ".bad", sizeof(badpath)-strlen(badpath)-1);
2980 badpath[sizeof(badpath)-1] = '\0';
2981 #ifdef _WIN32
2982 wchar_t* wpath = utf8_to_wchar(path);
2983 wchar_t* wbadpath = utf8_to_wchar(badpath);
2984 wchar_t* wsavepath = NULL;
2985 if (!_wrename(wpath, wbadpath)) {
2986 #else
2987 if (!rename(path, badpath)) {
2988 #endif
2989 strncpy(savepath, path, sizeof(savepath));
2990 strncat(savepath, ".save", sizeof(savepath)-strlen(savepath)-1);
2991 savepath[sizeof(savepath)-1] = '\0';
2992 #ifdef _WIN32
2993 wsavepath = utf8_to_wchar(savepath);
2994 if (_wrename(wsavepath, wpath)) // didn't work
2995 _wrename(wbadpath, wpath);
2996 #else
2997 if (rename(savepath, path)) // didn't work
2998 rename(badpath, path);
2999 #endif
3000 else
3001 #ifdef _WIN32
3002 {
3003 _wunlink(wbadpath);
3004 free_wchar(wpath);
3005 free_wchar(wbadpath);
3006 if (wsavepath) free_wchar(wsavepath);
3007 }
3008 #else
3009 unlink(badpath);
3010 #endif
3011 }
3012 goto imp_end;
3013 }
3014 }
3015
3016 if (rval == 0) {
3017 tQSL_Error = TQSL_NO_ERROR;
3018 strncpy(tQSL_ImportCall, ImportCall, sizeof tQSL_ImportCall);
3019 } else {
3020 if (tQSL_Error == 0) {
3021 tQSL_Error = TQSL_CERT_ERROR;
3022 }
3023 }
3024 imp_end:
3025 if (p12)
3026 PKCS12_free(p12);
3027 if (in)
3028 BIO_free(in);
3029 if (bags)
3030 sk_PKCS12_SAFEBAG_pop_free(bags, PKCS12_SAFEBAG_free);
3031 if (safes)
3032 sk_PKCS7_pop_free(safes, PKCS7_free);
3033 if (obj)
3034 ASN1_OBJECT_free(obj);
3035 if (callobj)
3036 ASN1_OBJECT_free(callobj);
3037 if (bs)
3038 BASIC_CONSTRAINTS_free(bs);
3039 if (p8)
3040 PKCS8_PRIV_KEY_INFO_free(p8);
3041 if (pkey)
3042 EVP_PKEY_free(pkey);
3043 return rval;
3044 }
3045
3046 DLLEXPORT int CALLCONVENTION
3047 tqsl_importPKCS12File(const char *filename, const char *p12password, const char *password,
3048 int (*pwcb)(char *, int, void *), int(*cb)(int, const char *, void *), void *userdata) {
3049 tqslTrace("tqsl_importPKCS12File", NULL);
3050 return tqsl_importPKCS12(false, filename, NULL, p12password, password, pwcb, cb, userdata);
3051 }
3052
3053 DLLEXPORT int CALLCONVENTION
3054 tqsl_importPKCS12Base64(const char *base64, const char *p12password, const char *password,
3055 int (*pwcb)(char *, int, void *), int(*cb)(int, const char *, void *), void *userdata) {
3056 tqslTrace("tqsl_importPKCS12Base64", NULL);
3057 return tqsl_importPKCS12(true, NULL, base64, p12password, password, pwcb, cb, userdata);
3058 }
3059
3060 static int
3061 tqsl_backup_cert(tQSL_Cert cert) {
3062 char callsign[64];
3063 long serial = 0;
3064 int dxcc = 0;
3065 int keyonly;
3066 tqsl_getCertificateKeyOnly(cert, &keyonly);
3067 tqsl_getCertificateCallSign(cert, callsign, sizeof callsign);
3068 if (!keyonly)
3069 tqsl_getCertificateSerial(cert, &serial);
3070 tqsl_getCertificateDXCCEntity(cert, &dxcc);
3071
3072 #ifndef PATH_MAX
3073 #define PATH_MAX 1024
3074 #endif
3075 char backupPath[PATH_MAX];
3076 tqsl_make_backup_path(callsign, backupPath, sizeof backupPath);
3077
3078 FILE* out = NULL;
3079 #ifdef _WIN31
3080 wchar_t* wpath = utf8_to_wchar(backupPath);
3081 _wunlink(wpath);
3082 fd = _wfopen(lfn, L"wb");
3083 free_wchar(wpath);
3084 #else
3085 unlink(backupPath);
3086 out = fopen(backupPath, "wb");
3087 #endif
3088 if (!out) {
3089 tQSL_Error = TQSL_SYSTEM_ERROR;
3090 tQSL_Errno = errno;
3091 strncpy(tQSL_ErrorFile, backupPath, sizeof tQSL_ErrorFile);
3092 tQSL_ErrorFile[sizeof tQSL_ErrorFile-1] = 0;
3093 tqslTrace("tqsl_backup_cert", "Error %d errno %d file %s", tQSL_Error, tQSL_Errno, backupPath);
3094 return 1;
3095 }
3096 char buf[8192];
3097 fprintf(out, "<UserCert CallSign=\"%s\" dxcc=\"%d\" serial=\"%ld\">\n", callsign, dxcc, serial);
3098 if (!keyonly) {
3099 fprintf(out, "<SignedCert>\n");
3100 tqsl_getCertificateEncoded(cert, buf, sizeof buf);
3101 fprintf(out, "%s", buf);
3102 fprintf(out, "</SignedCert>\n");
3103 }
3104 fprintf(out, "<PrivateKey>\n");
3105 tqsl_getKeyEncoded(cert, buf, sizeof buf);
3106 fprintf(out, "%s", buf);
3107 fprintf(out, "</PrivateKey>\n</UserCert>\n");
3108 fclose(out);
3109 return 0;
3110 }
3111
3112 static int
3113 tqsl_make_backup_list(const char* filter, vector<string>& keys) {
3114 keys.clear();
3115
3116 string path = tQSL_BaseDir;
3117 #ifdef _WIN32
3118 path += "\\certtrash";
3119 wchar_t* wpath = utf8_to_wchar(path.c_str());
3120 MKDIR(wpath, 0700);
3121 #else
3122 path += "/certtrash";
3123 MKDIR(path.c_str(), 0700);
3124 #endif
3125
3126 #ifdef _WIN32
3127 WDIR *dir = wopendir(wpath);
3128 free_wchar(wpath);
3129 #else
3130 DIR *dir = opendir(path.c_str());
3131 #endif
3132 if (dir == NULL) {
3133 tQSL_Error = TQSL_SYSTEM_ERROR;
3134 tQSL_Errno = errno;
3135 tqslTrace("tqsl_make_backup_list", "Opendir %s error %s", path.c_str(), strerror(errno));
3136 return 1;
3137 }
3138 #ifdef _WIN32
3139 struct wdirent *ent;
3140 #else
3141 struct dirent *ent;
3142 #endif
3143 int rval = 0;
3144 int savedError = 0;
3145 int savedErrno = 0;
3146 char *savedFile = NULL;
3147
3148 #ifdef _WIN32
3149 while ((ent = wreaddir(dir)) != NULL) {
3150 if (ent->d_name[0] == '.')
3151 continue;
3152 char dname[TQSL_MAX_PATH_LEN];
3153 wcstombs(dname, ent->d_name, TQSL_MAX_PATH_LEN);
3154 string filename = path + "\\" + dname;
3155 struct _stat32 s;
3156 wchar_t* wfilename = utf8_to_wchar(filename.c_str());
3157 if (_wstat32(wfilename, &s) == 0) {
3158 if (S_ISDIR(s.st_mode)) {
3159 free_wchar(wfilename);
3160 continue; // If it's a directory, skip it.
3161 }
3162 }
3163 #else
3164 while ((ent = readdir(dir)) != NULL) {
3165 if (ent->d_name[0] == '.')
3166 continue;
3167 string filename = path + "/" + ent->d_name;
3168 struct stat s;
3169 if (stat(filename.c_str(), &s) == 0) {
3170 if (S_ISDIR(s.st_mode))
3171 continue; // If it's a directory, skip it.
3172 }
3173 #endif
3174 XMLElement xel;
3175 int status = xel.parseFile(filename.c_str());
3176 if (status)
3177 continue; // Can't be parsed
3178
3179 XMLElement cert;
3180 xel.getFirstElement(cert);
3181 pair<string, bool> atrval = cert.getAttribute("CallSign");
3182 if (atrval.second) {
3183 // If the callsign matches, or if the filter is empty, add it.
3184 if (filter == NULL || atrval.first == filter) {
3185 keys.push_back(atrval.first);
3186 }
3187 }
3188 }
3189 #ifdef _WIN32
3190 _wclosedir(dir);
3191 #else
3192 closedir(dir);
3193 #endif
3194 if (rval) {
3195 tQSL_Error = savedError;
3196 tQSL_Errno = savedErrno;
3197 if (savedFile) {
3198 strncpy(tQSL_ErrorFile, savedFile, sizeof tQSL_ErrorFile);
3199 free(savedFile);
3200 }
3201 tqslTrace("tqsl_make_backup_list", "error %s %s", tQSL_ErrorFile, strerror(tQSL_Errno));
3202 }
3203 return rval;
3204 }
3205
3206 DLLEXPORT int CALLCONVENTION
3207 tqsl_deleteCertificate(tQSL_Cert cert) {
3208 tqslTrace("tqsl_deleteCertificate", NULL);
3209
3210 if (tqsl_init())
3211 return 1;
3212 if (cert == NULL || !tqsl_cert_check(TQSL_API_TO_CERT(cert), false)) {
3213 tqslTrace("tqsl_deleteCertificate", "arg err cert=0x%lx", cert);
3214 tQSL_Error = TQSL_ARGUMENT_ERROR;
3215 return 1;
3216 }
3217
3218 tqsl_backup_cert(cert);
3219 char callsign[256], path[256], newpath[256];
3220 if (tqsl_getCertificateCallSign(cert, callsign, sizeof callsign)) {
3221 tqslTrace("tqsl_deleteCertificate", "no callsign %d", tQSL_Error);
3222 return 1;
3223 }
3224
3225 int rval = 1;
3226 EVP_PKEY *key = 0;
3227 BIO *bio = 0;
3228 tQSL_Error = TQSL_OPENSSL_ERROR;
3229
3230 // Delete private key
3231 map<string, string> rec;
3232 if (TQSL_API_TO_CERT(cert)->pubkey) {
3233 rec["PUBLIC_KEY"] = TQSL_API_TO_CERT(cert)->pubkey;
3234 } else {
3235 // Get public key from cert
3236 if ((key = X509_get_pubkey(TQSL_API_TO_CERT(cert)->cert)) == 0) {
3237 tqslTrace("tqsl_deleteCertificate", "no public key %s", tqsl_openssl_error());
3238 goto dc_end;
3239 }
3240 if ((bio = BIO_new(BIO_s_mem())) == NULL) {
3241 tqslTrace("tqsl_deleteCertificate", "bio err %s", tqsl_openssl_error());
3242 goto dc_end;
3243 }
3244 if (!PEM_write_bio_PUBKEY(bio, key)) {
3245 tqslTrace("tqsl_deleteCertificate", "bio write err %s", tqsl_openssl_error());
3246 goto dc_end;
3247 }
3248 char *cp;
3249 int len = static_cast<int>(BIO_get_mem_data(bio, &cp));
3250 rec["PUBLIC_KEY"] = string(cp, len);
3251 BIO_free(bio);
3252 bio = 0;
3253 EVP_PKEY_free(key);
3254 key = 0;
3255 }
3256 rec["CALLSIGN"] = callsign;
3257 if (!tqsl_make_key_path(callsign, path, sizeof path)) {
3258 tqslTrace("tqsl_deleteCertificate", "key path err %s", tQSL_Error);
3259 goto dc_end;
3260 }
3261 // Since there is no private key in "rec," tqsl_replace_key will just remove the
3262 // existing private key.
3263 tqsl_replace_key(callsign, path, rec, 0, 0);
3264
3265 if (TQSL_API_TO_CERT(cert)->keyonly) {
3266 tqslTrace("tqsl_deleteCertificate", "key only");
3267 goto dc_ok;
3268 }
3269
3270 // Now the certificate
3271
3272 tqsl_make_cert_path("user", path, sizeof path);
3273 tqsl_make_cert_path("user.new", newpath, sizeof newpath);
3274 if (xcerts == NULL) {
3275 if ((xcerts = tqsl_ssl_load_certs_from_file(path)) == 0) {
3276 tqslTrace("tqsl_deleteCertificate", "error reading certs %d", tQSL_Error);
3277 goto dc_end;
3278 }
3279 }
3280 if ((bio = BIO_new_file(newpath, "wb")) == 0) {
3281 tqslTrace("tqsl_deleteCertificate", "bio_new_file %s", tqsl_openssl_error());
3282 goto dc_end;
3283 }
3284 X509 *x;
3285 while ((x = sk_X509_shift(xcerts)) != 0) {
3286 if (X509_issuer_and_serial_cmp(x, TQSL_API_TO_CERT(cert)->cert)) {
3287 if (!PEM_write_bio_X509(bio, x)) { // No match -- keep this one
3288 tqslTrace("tqsl_deleteCertificate", "pem_write_bio %s", tqsl_openssl_error());
3289 goto dc_end;
3290 }
3291 }
3292 }
3293 BIO_free(bio);
3294 bio = 0;
3295
3296 // Looks like the new file is okay, commit it
3297 #ifdef _WIN32
3298 wchar_t* wpath = utf8_to_wchar(path);
3299 if (_wunlink(wpath) && errno != ENOENT) {
3300 free_wchar(wpath);
3301 #else
3302 if (unlink(path) && errno != ENOENT) {
3303 #endif
3304 tQSL_Error = TQSL_SYSTEM_ERROR;
3305 tQSL_Errno = errno;
3306 tqslTrace("tqsl_deleteCertificate", "unlink err %d", errno);
3307 goto dc_end;
3308 }
3309 #ifdef _WIN32
3310 wchar_t* wnewpath = utf8_to_wchar(newpath);
3311 if (_wrename(wnewpath, wpath)) {
3312 free_wchar(wpath);
3313 free_wchar(wnewpath);
3314 #else
3315 if (rename(newpath, path)) {
3316 #endif
3317 tQSL_Error = TQSL_SYSTEM_ERROR;
3318 tQSL_Errno = errno;
3319 tqslTrace("tqsl_deleteCertificate", "rename err %d", errno);
3320 goto dc_end;
3321 }
3322 #ifdef _WIN32
3323 free(wpath);
3324 free(wnewpath);
3325 #endif
3326
3327 dc_ok:
3328 rval = 0;
3329 tQSL_Error = TQSL_NO_ERROR;
3330
3331 dc_end:
3332 if (xcerts) {
3333 sk_X509_free(xcerts);
3334 xcerts = NULL;
3335 }
3336 if (key)
3337 EVP_PKEY_free(key);
3338 if (bio)
3339 BIO_free(bio);
3340 return rval;
3341 }
3342
3343 /** Get the list of restorable callsign certificates. */
3344 DLLEXPORT int CALLCONVENTION
3345 tqsl_getDeletedCallsignCertificates(char ***calls, int *ncall, const char *filter) {
3346 vector <string> callsigns;
3347
3348 if (tqsl_make_backup_list(filter, callsigns)) {
3349 return 1;
3350 }
3351 *ncall = callsigns.size();
3352 if (*ncall == 0) {
3353 if (calls) {
3354 *calls = NULL;
3355 }
3356 return 0;
3357 }
3358 if (calls == NULL) {
3359 return 0;
3360 }
3361 *calls = reinterpret_cast<char **>(calloc(*ncall, sizeof(**calls)));
3362 vector<string>::iterator it;
3363 char **p = *calls;
3364 for (it = callsigns.begin(); it != callsigns.end(); it++) {
3365 *p++ = strdup((*it).c_str());
3366 }
3367 return 0;
3368 }
3369
3370 DLLEXPORT void CALLCONVENTION
3371 tqsl_freeDeletedCertificateList(char **list, int nloc) {
3372 if (!list) return;
3373 for (int i = 0; i < nloc; i++)
3374 if (list[i]) free(list[i]);
3375 if (list) free(list);
3376 }
3377
3378 /** Restore a deleted callsign certificate by callsign. */
3379 DLLEXPORT int CALLCONVENTION
3380 tqsl_restoreCallsignCertificate(const char *callsign) {
3381 tqslTrace("tqsl_restoreCallsignCertificate", "callsign = %s", callsign);
3382 char backupPath[PATH_MAX];
3383 tqsl_make_backup_path(callsign, backupPath, sizeof backupPath);
3384
3385 XMLElement xel;
3386 int status = xel.parseFile(backupPath);
3387 if (status) {
3388 if (errno == ENOENT) { // No file is OK
3389 tqslTrace("tqsl_restoreCallsignCertificate", "FNF");
3390 return 0;
3391 }
3392 strncpy(tQSL_ErrorFile, backupPath, sizeof tQSL_ErrorFile);
3393 if (status == XML_PARSE_SYSTEM_ERROR) {
3394 tQSL_Error = TQSL_FILE_SYSTEM_ERROR;
3395 tQSL_Errno = errno;
3396 tqslTrace("tqsl_restoreCallsignCertificate", "open error %s: %s", backupPath, strerror(tQSL_Errno));
3397 } else {
3398 tqslTrace("tqsl_restoreCallsignCertificate", "syntax error %s", backupPath);
3399 tQSL_Error = TQSL_FILE_SYNTAX_ERROR;
3400 }
3401 return 1;
3402 }
3403 XMLElement cert;
3404 string call;
3405 int dxcc = 0;
3406 long serial = 0;
3407 string privateKey;
3408 string publicKey;
3409 XMLElementList& ellist = xel.getElementList();
3410 XMLElementList::iterator ep;
3411 for (ep = ellist.find("UserCert"); ep != ellist.end(); ep++) {
3412 if (ep->first != "UserCert")
3413 break;
3414 pair<string, bool> rval = ep->second->getAttribute("CallSign");
3415 if (rval.second) call = rval.first;
3416 rval = ep->second->getAttribute("serial");
3417 if (rval.second) serial = strtol(rval.first.c_str(), NULL, 10);
3418 rval = ep->second->getAttribute("dxcc");
3419 if (rval.second) dxcc = strtol(rval.first.c_str(), NULL, 10);
3420
3421 XMLElement el;
3422 if (ep->second->getFirstElement("SignedCert", el)) {
3423 publicKey = el.getText();
3424 }
3425 if (ep->second->getFirstElement("PrivateKey", el)) {
3426 privateKey = el.getText();
3427 }
3428 }
3429
3430 // See if this certificate exists
3431 tQSL_Cert *certlist;
3432 int ncerts;
3433 tqsl_selectCertificates(&certlist, &ncerts, call.c_str(), dxcc, 0, 0, TQSL_SELECT_CERT_EXPIRED|TQSL_SELECT_CERT_SUPERCEDED|TQSL_SELECT_CERT_WITHKEYS);
3434 for (int i = 0; i < ncerts; i++) {
3435 long s = 0;
3436 int keyonly = false;
3437 tqsl_getCertificateKeyOnly(certlist[i], &keyonly);
3438 if (keyonly) {
3439 if (serial != 0) { // A full cert for this was imported
3440 continue;
3441 }
3442 }
3443 if (tqsl_getCertificateSerial(certlist[i], &s)) {
3444 continue;
3445 }
3446 if (s == serial) { // Already imported
3447 tqsl_freeCertificateList(certlist, ncerts);
3448 tQSL_Error = TQSL_CUSTOM_ERROR;
3449 strncpy(tQSL_CustomError, "This callsign certificate is already active and cannot be restored.",
3450 sizeof tQSL_CustomError);
3451 tqslTrace("tqsl_restoreCallsignCertificate", "certificate already exists");
3452 return 1;
3453 }
3454 }
3455 tqsl_freeCertificateList(certlist, ncerts);
3456 int stat = tqsl_importKeyPairEncoded(call.c_str(), "user", privateKey.c_str(), publicKey.c_str());
3457 if (!stat) {
3458 // Remove the backup file
3459 #ifdef _WIN32
3460 wchar_t* wbpath = utf8_to_wchar(backupPath);
3461 _wunlink(wbpath);
3462 free_wchar(wbpath);
3463 #else
3464 unlink(backupPath);
3465 #endif
3466 }
3467 return stat;
3468 }
3469
3470 /********** END OF PUBLIC API FUNCTIONS **********/
3471
3472 /* Utility functions to manage private data structures */
3473
3474 static int
3475 tqsl_check_crq_field(tQSL_Cert cert, char *buf, int bufsiz) {
3476 if (tqsl_init())
3477 return 1;
3478 if (cert == NULL || buf == NULL || bufsiz < 0 || !tqsl_cert_check(TQSL_API_TO_CERT(cert))) {
3479 tqslTrace("tqsl_check_crq_field", "arg err cert=0x%lx buf=0x%lx bufsiz=%d", cert, buf, bufsiz);
3480 tQSL_Error = TQSL_ARGUMENT_ERROR;
3481 return 1;
3482 }
3483 if (TQSL_API_TO_CERT(cert)->crq == NULL) {
3484 if (tqsl_find_matching_key(TQSL_API_TO_CERT(cert)->cert, NULL,
3485 &(TQSL_API_TO_CERT(cert)->crq), "", NULL, NULL) && tQSL_Error != TQSL_PASSWORD_ERROR) {
3486 tqslTrace("tqsl_check_crq_field", "can't find matching key err %d", tQSL_Error);
3487 return 1;
3488 }
3489 }
3490 return 0;
3491 }
3492
3493 static int
3494 tqsl_cert_check(tqsl_cert *p, bool needcert) {
3495 if (p != NULL && p->id == 0xCE && (!needcert || p->cert != NULL))
3496 return 1;
3497 tQSL_Error = TQSL_ARGUMENT_ERROR;
3498 return 0;
3499 }
3500
3501 static tqsl_cert *
3502 tqsl_cert_new() {
3503 tqsl_cert *p;
3504
3505 p = reinterpret_cast<tqsl_cert *>(tqsl_calloc(1, sizeof(tqsl_cert)));
3506 if (p != NULL)
3507 p->id = 0xCE;
3508 return p;
3509 }
3510
3511 static void
3512 tqsl_cert_free(tqsl_cert *p) {
3513 if (p == NULL || p->id != 0xCE)
3514 return;
3515 p->id = 0;
3516 if (p->cert != NULL)
3517 X509_free(p->cert);
3518 if (p->key != NULL)
3519 EVP_PKEY_free(p->key);
3520 if (p->crq != NULL)
3521 tqsl_free_cert_req(p->crq, 0);
3522 if (p->pubkey != NULL)
3523 delete[] p->pubkey;
3524 if (p->privkey != NULL)
3525 delete[] p->privkey;
3526 tqsl_free(p);
3527 }
3528
3529 static TQSL_CERT_REQ *
3530 tqsl_free_cert_req(TQSL_CERT_REQ *req, int seterr) {
3531 if (req == NULL)
3532 return NULL;
3533 tqsl_free(req);
3534 if (seterr)
3535 tQSL_Error = seterr;
3536 return NULL;
3537 }
3538
3539 static TQSL_CERT_REQ *
3540 tqsl_copy_cert_req(TQSL_CERT_REQ *userreq) {
3541 TQSL_CERT_REQ *req;
3542
3543 if ((req = reinterpret_cast<TQSL_CERT_REQ *>(tqsl_calloc(1, sizeof(TQSL_CERT_REQ)))) == NULL) {
3544 tqslTrace("tqsl_copy_cert_req", "ENOMEM");
3545 errno = ENOMEM;
3546 return NULL;
3547 }
3548 *req = *userreq;
3549 return req;
3550 }
3551
3552 static int
3553 tqsl_check_parm(const char *p, const char *parmName) {
3554 if (strlen(p) == 0) {
3555 tQSL_Error = TQSL_CUSTOM_ERROR;
3556 snprintf(tQSL_CustomError, sizeof tQSL_CustomError,
3557 "Missing parameter: %s", parmName);
3558 tqslTrace("tqsl_check_parm", "error %s", tQSL_CustomError);
3559 return 1;
3560 }
3561 return 0;
3562 }
3563
3564 static char *
3565 tqsl_trim(char *buf) {
3566 char lastc;
3567 char *cp, *op;
3568
3569 /* Trim white space off end of string */
3570 cp = buf + strlen(buf);
3571 while (cp != buf) {
3572 cp--;
3573 if (!isspace(*cp))
3574 break;
3575 *cp = 0;
3576 }
3577 /* Skip past leading whitespace */
3578 for (cp = buf; isspace(*cp); cp++)
3579 {}
3580 /* Fold runs of white space into single space */
3581 lastc = 0;
3582 op = buf;
3583 for (; *cp != '\0'; cp++) {
3584 if (isspace(*cp))
3585 *cp = ' ';
3586 if (*cp != ' ' || lastc != ' ')
3587 *op++ = *cp;
3588 lastc = *cp;
3589 }
3590 *op = '\0';
3591 return cp;
3592 }
3593 /* Filter a list (stack) of X509 certs based on call sign, QSO date and/or
3594 * issuer.
3595 *
3596 * Returns a new stack of matching certs without altering the original stack.
3597 *
3598 * Note that you don't have to supply any of the criteria. If you supply
3599 * none, you;ll just get back an exact copy of the stack.
3600 */
3601 CLIENT_STATIC STACK_OF(X509) *
3602 tqsl_filter_cert_list(STACK_OF(X509) *sk, const char *callsign, int dxcc,
3603 const tQSL_Date *date, const TQSL_PROVIDER *issuer, int flags) {
3604 set<string> superceded_certs;
3605
3606 char buf[256], name_buf[256];
3607 TQSL_X509_NAME_ITEM item;
3608 X509 *x;
3609 STACK_OF(X509) *newsk;
3610 int i, ok, len;
3611 tQSL_Date qso_date;
3612
3613 tqslTrace("tqsl_filter_cert_list", NULL);
3614 if (tqsl_init())
3615 return NULL;
3616 if ((newsk = sk_X509_new_null()) == NULL) {
3617 tqslTrace("tqsl_filter_cert_list", "sk_X509_new_null err %s", tqsl_openssl_error());
3618 return NULL;
3619 }
3620 tqsl_cert* cp = tqsl_cert_new();
3621 /* Loop through the list of certs */
3622 for (i = 0; i < sk_X509_num(sk); i++) {
3623 ok = 1; /* Certificate is selected unless some check says otherwise */
3624 x = sk_X509_value(sk, i);
3625 cp->cert = x;
3626 /* Check for expired unless asked not to */
3627 if (ok && !(flags & TQSL_SELECT_CERT_EXPIRED)) {
3628 int exp = false;
3629 if (!tqsl_isCertificateExpired(TQSL_OBJ_TO_API(cp), &exp)) {
3630 if (exp) {
3631 ok = 0;
3632 }
3633 }
3634 }
3635 /* Check for superceded unless asked not to */
3636 if (ok && !(flags & TQSL_SELECT_CERT_SUPERCEDED)) {
3637 int sup = false;
3638 if (!tqsl_isCertificateSuperceded(TQSL_OBJ_TO_API(cp), &sup)) {
3639 if (sup) {
3640 ok = 0;
3641 }
3642 }
3643 }
3644 /* Compare issuer if asked to */
3645 if (ok && issuer != NULL) {
3646 X509_NAME *iss;
3647 if ((iss = X509_get_issuer_name(x)) == NULL)
3648 ok = 0;
3649 if (ok) {
3650 item.name_buf = name_buf;
3651 item.name_buf_size = sizeof name_buf;
3652 item.value_buf = buf;
3653 item.value_buf_size = sizeof buf;
3654 tqsl_get_name_entry(iss, "organizationName", &item);
3655 ok = !strcmp(issuer->organizationName, item.value_buf);
3656 }
3657 if (ok) {
3658 item.name_buf = name_buf;
3659 item.name_buf_size = sizeof name_buf;
3660 item.value_buf = buf;
3661 item.value_buf_size = sizeof buf;
3662 tqsl_get_name_entry(iss, "organizationalUnitName", &item);
3663 ok = !strcmp(issuer->organizationalUnitName, item.value_buf);
3664 }
3665 }
3666 /* Check call sign if asked */
3667 if (ok && callsign != NULL) {
3668 item.name_buf = name_buf;
3669 item.name_buf_size = sizeof name_buf;
3670 item.value_buf = buf;
3671 item.value_buf_size = sizeof buf;
3672 if (!tqsl_cert_get_subject_name_entry(x, "AROcallsign", &item))
3673 ok = 0;
3674 else
3675 ok = !strcmp(callsign, item.value_buf);
3676 }
3677 /* Check DXCC entity if asked */
3678 if (ok && dxcc > 0) {
3679 len = sizeof buf-1;
3680 if (tqsl_get_cert_ext(x, "dxccEntity", (unsigned char *)buf, &len, NULL)) {
3681 ok = 0;
3682 } else {
3683 buf[len] = 0;
3684 if (dxcc != strtol(buf, NULL, 10))
3685 ok = 0;
3686 }
3687 }
3688 /* Check QSO date if asked */
3689 if (ok && date != NULL && !tqsl_isDateNull(date)) {
3690 len = sizeof buf-1;
3691 if (tqsl_get_cert_ext(x, "QSONotBeforeDate", (unsigned char *)buf, &len, NULL))
3692 ok = 0;
3693 else if (tqsl_initDate(&qso_date, buf))
3694 ok = 0;
3695 else if (tqsl_compareDates(date, &qso_date) < 0)
3696 ok = 0;
3697 }
3698 if (ok && date != NULL && !tqsl_isDateNull(date)) {
3699 len = sizeof buf-1;
3700 if (tqsl_get_cert_ext(x, "QSONotAfterDate", (unsigned char *)buf, &len, NULL))
3701 ok = 0;
3702 else if (tqsl_initDate(&qso_date, buf))
3703 ok = 0;
3704 else if (tqsl_compareDates(date, &qso_date) > 0)
3705 ok = 0;
3706 }
3707 /* If no check failed, copy this cert onto the new stack */
3708 if (ok)
3709 sk_X509_push(newsk, X509_dup(x));
3710 }
3711 tqsl_free(cp);
3712 return newsk;
3713 }
3714
3715
3716 /* Set up a read-only BIO from the given file and pass to
3717 * tqsl_ssl_load_certs_from_BIO.
3718 */
3719 CLIENT_STATIC STACK_OF(X509) *
3720 tqsl_ssl_load_certs_from_file(const char *filename) {
3721 BIO *in;
3722 STACK_OF(X509) *sk;
3723 FILE *cfile;
3724
3725 tqslTrace("tqsl_ssl_load_certs_from_file", "filename=%s", filename);
3726
3727 #ifdef _WIN32
3728 wchar_t* wfilename = utf8_to_wchar(filename);
3729 if ((cfile = _wfopen(wfilename, L"r")) == NULL) {
3730 free_wchar(wfilename);
3731 #else
3732 if ((cfile = fopen(filename, "r")) == NULL) {
3733 #endif
3734 strncpy(tQSL_ErrorFile, filename, sizeof tQSL_ErrorFile);
3735 tQSL_Error = TQSL_SYSTEM_ERROR;
3736 tQSL_Errno = errno;
3737 tqslTrace("tqsl_ssl_load_certs_from_file", "File open error %s", strerror(errno));
3738 return NULL;
3739 }
3740 #ifdef _WIN32
3741 free(wfilename);
3742 #endif
3743 if ((in = BIO_new_fp(cfile, 0)) == NULL) {
3744 tQSL_Error = TQSL_OPENSSL_ERROR;
3745 tqslTrace("tqsl_ssl_load_certs_from_file", "bio_new_fp err %s", tqsl_openssl_error());
3746 return NULL;
3747 }
3748 sk = tqsl_ssl_load_certs_from_BIO(in);
3749 BIO_free(in);
3750 fclose(cfile);
3751 return sk;
3752 }
3753
3754 /* Load a set of certs from a file into a stack. The file may contain
3755 * other X509 objects (e.g., CRLs), but we'll ignore those.
3756 *
3757 * Return NULL if there are no certs in the file or on error.
3758 */
3759 CLIENT_STATIC STACK_OF(X509) *
3760 tqsl_ssl_load_certs_from_BIO(BIO *in) {
3761 STACK_OF(X509_INFO) *sk = NULL;
3762 STACK_OF(X509) *stack = NULL;
3763 X509_INFO *xi;
3764
3765 if (tqsl_init())
3766 return NULL;
3767 if (!(stack = sk_X509_new_null())) {
3768 tqslTrace("tqsl_ssl_load_certs_from_BIO", "bio_new_fp err %s", tqsl_openssl_error());
3769 tQSL_Error = TQSL_OPENSSL_ERROR;
3770 return NULL;
3771 }
3772 if (!(sk = PEM_X509_INFO_read_bio(in, NULL, NULL, NULL))) {
3773 sk_X509_free(stack);
3774 tqslTrace("tqsl_ssl_load_certs_from_BIO", "PEM_X509_INFO_read_bio err %s", tqsl_openssl_error());
3775 tQSL_Error = TQSL_OPENSSL_ERROR;
3776 return NULL;
3777 }
3778 /* Extract the certs from the X509_INFO objects and put them on a stack */
3779 while (sk_X509_INFO_num(sk)) {
3780 xi = sk_X509_INFO_shift(sk);
3781 if (xi->x509 != NULL) {
3782 sk_X509_push(stack, xi->x509);
3783 xi->x509 = NULL;
3784 }
3785 X509_INFO_free(xi);
3786 }
3787 /* Empty file isn't really an error, is it?
3788 if(!sk_X509_num(stack)) {
3789 sk_X509_free(stack);
3790 stack = NULL;
3791 strcpy(tQSL_CustomError, "No certificates found");
3792 tQSL_Error = TQSL_CUSTOM_ERROR;
3793 }
3794 */
3795 sk_X509_INFO_free(sk);
3796 return stack;
3797 }
3798
3799 /* Chain-verify a cert against a set of CA and a set of trusted root certs.
3800 *
3801 * Returns NULL if cert verifies, an error message if it does not.
3802 */
3803 CLIENT_STATIC const char *
3804 tqsl_ssl_verify_cert(X509 *cert, STACK_OF(X509) *cacerts, STACK_OF(X509) *rootcerts, int purpose,
3805 int (*cb)(int ok, X509_STORE_CTX *ctx), STACK_OF(X509) **chain) {
3806 X509_STORE *store;
3807 X509_STORE_CTX *ctx;
3808 int rval;
3809 const char *errm;
3810
3811 if (cert == NULL) {
3812 tqslTrace("tqsl_ssl_verify_cert", "No certificate to verify");
3813 return "No certificate to verify";
3814 }
3815 if (tqsl_init())
3816 return NULL;
3817 store = X509_STORE_new();
3818 if (store == NULL) {
3819 tqslTrace("tqsl_ssl_verify_cert", "out of memory");
3820 return "Out of memory";
3821 }
3822 if (cb != NULL)
3823 X509_STORE_set_verify_cb(store, cb);
3824 ctx = X509_STORE_CTX_new();
3825 if (ctx == NULL) {
3826 X509_STORE_free(store);
3827 tqslTrace("tqsl_ssl_verify_cert", "store_ctx_new out of memory");
3828 return "Out of memory";
3829 }
3830 X509_STORE_CTX_init(ctx, store, cert, cacerts);
3831 if (cb != NULL)
3832 X509_STORE_CTX_set_verify_cb(ctx, cb);
3833 if (rootcerts)
3834 X509_STORE_CTX_trusted_stack(ctx, rootcerts);
3835 if (purpose >= 0)
3836 X509_STORE_CTX_set_purpose(ctx, purpose);
3837 X509_STORE_CTX_set_flags(ctx, X509_V_FLAG_CB_ISSUER_CHECK);
3838 rval = X509_verify_cert(ctx);
3839 errm = X509_verify_cert_error_string(X509_STORE_CTX_get_error(ctx));
3840 #if OPENSSL_VERSION_NUMBER < 0x10100000L
3841 #define X509_STORE_CTX_get0_chain(o) ((o)->chain)
3842 #endif
3843 if (chain) {
3844 if (rval && X509_STORE_CTX_get0_chain(ctx))
3845 *chain = sk_X509_dup(X509_STORE_CTX_get0_chain(ctx));
3846 else
3847 *chain = 0;
3848 }
3849 X509_STORE_CTX_free(ctx);
3850 if (rval)
3851 return NULL;
3852 if (errm != NULL) {
3853 tqslTrace("tqsl_ssl_verify_cert", "err %s", errm);
3854 return errm;
3855 }
3856 return "Verification failed";
3857 }
3858
3859 /* [static] - Grab the data from an X509_NAME_ENTRY and put it into
3860 * a TQSL_X509_NAME_ITEM object, checking buffer sizes.
3861 *
3862 * Returns 0 on error, 1 if okay.
3863 *
3864 * It's okay for the name_buf or value_buf item of the object to
3865 * be NULL; it'll just be skipped.
3866 */
3867 static int
3868 tqsl_get_name_stuff(X509_NAME_ENTRY *entry, TQSL_X509_NAME_ITEM *name_item) {
3869 ASN1_OBJECT *obj;
3870 ASN1_STRING *value;
3871 const char *val;
3872 unsigned int len;
3873
3874 if (entry == NULL) {
3875 tqslTrace("tqsl_get_name_stuff", "entry=null");
3876 tQSL_Error = TQSL_ARGUMENT_ERROR;
3877 return 0;
3878 }
3879 obj = X509_NAME_ENTRY_get_object(entry);
3880 if (obj == NULL) {
3881 tqslTrace("tqsl_get_name_stuff", "get_object err %s", tqsl_openssl_error());
3882 tQSL_Error = TQSL_OPENSSL_ERROR;
3883 return 0;
3884 }
3885 if (name_item->name_buf != NULL) {
3886 len = i2t_ASN1_OBJECT(name_item->name_buf, name_item->name_buf_size, obj);
3887 if (len <= 0 || len > strlen(name_item->name_buf)) {
3888 tqslTrace("tqsl_get_name_stuff", "len error len= %d need=%d", len, strlen(name_item->name_buf));
3889 tQSL_Error = TQSL_OPENSSL_ERROR;
3890 return 0;
3891 }
3892 }
3893 if (name_item->value_buf != NULL) {
3894 value = X509_NAME_ENTRY_get_data(entry);
3895 val = (const char *)ASN1_STRING_get0_data(value);
3896 strncpy(name_item->value_buf, val, name_item->value_buf_size);
3897 name_item->value_buf[name_item->value_buf_size-1] = '\0';
3898 if (strlen(val) > strlen(name_item->value_buf)) {
3899 tqslTrace("tqsl_get_name_stuff", "len error len= %d need=%d", strlen(val), strlen(name_item->value_buf));
3900 tQSL_Error = TQSL_OPENSSL_ERROR;
3901 return 0;
3902 }
3903 }
3904 return 1;
3905 }
3906
3907 /* Get a name entry from an X509_NAME by its name.
3908 */
3909 CLIENT_STATIC int
3910 tqsl_get_name_entry(X509_NAME *name, const char *obj_name, TQSL_X509_NAME_ITEM *name_item) {
3911 X509_NAME_ENTRY *entry;
3912 int num_entries, i;
3913
3914 if (tqsl_init())
3915 return 0;
3916 num_entries = X509_NAME_entry_count(name);
3917 if (num_entries <= 0)
3918 return 0;
3919 /* Loop through the name entries */
3920 for (i = 0; i < num_entries; i++) {
3921 entry = X509_NAME_get_entry(name, i);
3922 if (!tqsl_get_name_stuff(entry, name_item))
3923 continue;
3924 if (name_item->name_buf != NULL && !strcmp(name_item->name_buf, obj_name)) {
3925 /* Found the wanted entry */
3926 return 1;
3927 }
3928 }
3929 return 0;
3930 }
3931
3932 /* Get a name entry from a cert's subject name by its name.
3933 */
3934 CLIENT_STATIC int
3935 tqsl_cert_get_subject_name_entry(X509 *cert, const char *obj_name, TQSL_X509_NAME_ITEM *name_item) {
3936 X509_NAME *name;
3937
3938 if (cert == NULL)
3939 return 0;
3940 if (tqsl_init())
3941 return 0;
3942 if ((name = X509_get_subject_name(cert)) == NULL)
3943 return 0;
3944 return tqsl_get_name_entry(name, obj_name, name_item);
3945 }
3946
3947 /* Initialize the tQSL (really OpenSSL) random number generator
3948 * Return 0 on error.
3949 */
3950 CLIENT_STATIC int
3951 tqsl_init_random() {
3952 char fname[256];
3953 static int initialized = 0;
3954
3955 if (initialized)
3956 return 1;
3957 if (RAND_file_name(fname, sizeof fname) != NULL)
3958 RAND_load_file(fname, -1);
3959 initialized = RAND_status();
3960 if (!initialized) {
3961 tqslTrace("tqsl_init_random", "init error %s", tqsl_openssl_error());
3962 tQSL_Error = TQSL_RANDOM_ERROR;
3963 }
3964 return initialized;
3965 }
3966
3967 /* Generate an RSA key of at least 1024 bits length
3968 */
3969 CLIENT_STATIC EVP_PKEY *
3970 tqsl_new_rsa_key(int nbits) {
3971 EVP_PKEY *pkey;
3972
3973 if (nbits < 1024) {
3974 tqslTrace("tqsl_new_rsa_key", "nbits too small %d", nbits);
3975 tQSL_Error = TQSL_ARGUMENT_ERROR;
3976 return NULL;
3977 }
3978 if ((pkey = EVP_PKEY_new()) == NULL) {
3979 tqslTrace("tqsl_new_rsa_key", "EVP_PKEY_new err %s", tqsl_openssl_error());
3980 tQSL_Error = TQSL_OPENSSL_ERROR;
3981 return NULL;
3982 }
3983 if (!tqsl_init_random()) /* Unable to init RN generator */
3984 return NULL;
3985 RSA *rsa = RSA_new();
3986 if (rsa == NULL) {
3987 EVP_PKEY_free(pkey);
3988 tqslTrace("tqsl_new_rsa_key", "RSA_new err %s", tqsl_openssl_error());
3989 tQSL_Error = TQSL_OPENSSL_ERROR;
3990 return NULL;
3991 }
3992 BIGNUM *pubexp = BN_new();
3993 if (pubexp == NULL) {
3994 EVP_PKEY_free(pkey);
3995 RSA_free(rsa);
3996 tqslTrace("tqsl_new_rsa_key", "BN_new err %s", tqsl_openssl_error());
3997 tQSL_Error = TQSL_OPENSSL_ERROR;
3998 return NULL;
3999 }
4000 if (BN_set_word(pubexp, 0x10001) != 1) {
4001 EVP_PKEY_free(pkey);
4002 RSA_free(rsa);
4003 BN_free(pubexp);
4004 tqslTrace("tqsl_new_rsa_key", "BN_set_word err %s", tqsl_openssl_error());
4005 tQSL_Error = TQSL_OPENSSL_ERROR;
4006 return NULL;
4007 }
4008 if (RSA_generate_key_ex(rsa, nbits, pubexp, NULL) != 1) {
4009 EVP_PKEY_free(pkey);
4010 RSA_free(rsa);
4011 BN_free(pubexp);
4012 tqslTrace("tqsl_new_rsa_key", "RSA_generate_key err %s", tqsl_openssl_error());
4013 tQSL_Error = TQSL_OPENSSL_ERROR;
4014 return NULL;
4015 }
4016 if (!EVP_PKEY_assign_RSA(pkey, rsa)) {
4017 EVP_PKEY_free(pkey);
4018 RSA_free(rsa);
4019 BN_free(pubexp);
4020 tqslTrace("tqsl_new_rsa_key", "EVP_PKEY_assign_RSA err %s", tqsl_openssl_error());
4021 tQSL_Error = TQSL_OPENSSL_ERROR;
4022 return NULL;
4023 }
4024 BN_free(pubexp);
4025 return pkey;
4026 }
4027
4028
4029 /* Output an ADIF field to a file descriptor.
4030 */
4031 CLIENT_STATIC int
4032 tqsl_write_adif_field(FILE *fp, const char *fieldname, char type, const unsigned char *value, int len) {
4033 if (fieldname == NULL) /* Silly caller */
4034 return 0;
4035 if (fputc('<', fp) == EOF)
4036 return 1;
4037 if (fputs(fieldname, fp) == EOF)
4038 return 1;
4039 if (type && type != ' ' && type != '\0') {
4040 if (fputc(':', fp) == EOF)
4041 return 1;
4042 if (fputc(type, fp) == EOF)
4043 return 1;
4044 }
4045 if (value != NULL && len != 0) {
4046 if (len < 0)
4047 len = strlen((const char *)value);
4048 if (fputc(':', fp) == EOF)
4049 return 1;
4050 fprintf(fp, "%d>", len);
4051 if (fwrite(value, 1, len, fp) != (unsigned int) len)
4052 return 1;
4053 } else if (fputc('>', fp) == EOF) {
4054 return 1;
4055 }
4056 if (fputs("\n\n", fp) == EOF)
4057 return 1;
4058 return 0;
4059 }
4060
4061 /* Output an ADIF field to a BIO
4062 */
4063 CLIENT_STATIC int
4064 tqsl_bio_write_adif_field(BIO *bio, const char *fieldname, char type, const unsigned char *value, int len) {
4065 int bret;
4066 if (fieldname == NULL) /* Silly caller */
4067 return 0;
4068 if ((bret = BIO_write(bio, "<", 1)) <= 0)
4069 return 1;
4070 if ((bret = BIO_write(bio, fieldname, strlen(fieldname))) <= 0)
4071 return 1;
4072 if (type && type != ' ' && type != '\0') {
4073 if ((bret = BIO_write(bio, ":", 1)) <= 0)
4074 return 1;
4075 if ((bret = BIO_write(bio, &type, 1)) <= 0)
4076 return 1;
4077 }
4078 if (value != NULL && len != 0) {
4079 if (len < 0)
4080 len = strlen((const char *)value);
4081 if ((bret = BIO_write(bio, ":", 1)) <= 0)
4082 return 1;
4083 char numbuf[20];
4084 snprintf(numbuf, sizeof numbuf, "%d>", len);
4085 if ((bret = BIO_write(bio, numbuf, strlen(numbuf))) <= 0)
4086 return 1;
4087 if ((bret = BIO_write(bio, value, len)) != len)
4088 return 1;
4089 } else if ((bret = BIO_write(bio, ">", 1)) <= 0) {
4090 return 1;
4091 }
4092 if ((bret = BIO_write(bio, "\n\n", 2)) <= 0)
4093 return 1;
4094 return 0;
4095 }
4096
4097 static int
4098 tqsl_self_signed_is_ok(int ok, X509_STORE_CTX *ctx) {
4099 if (X509_STORE_CTX_get_error(ctx) == X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT)
4100 return 1;
4101 if (X509_STORE_CTX_get_error(ctx) == X509_V_ERR_CERT_UNTRUSTED)
4102 return 1;
4103 return ok;
4104 }
4105
4106 static int
4107 tqsl_expired_is_ok(int ok, X509_STORE_CTX *ctx) {
4108 if (X509_STORE_CTX_get_error(ctx) == X509_V_ERR_CERT_HAS_EXPIRED ||
4109 X509_STORE_CTX_get_error(ctx) == X509_V_ERR_CERT_UNTRUSTED)
4110 return 1;
4111 return ok;
4112 }
4113
4114 static char *
4115 tqsl_make_cert_path(const char *filename, char *path, int size) {
4116 strncpy(path, tQSL_BaseDir, size);
4117 #ifdef _WIN32
4118 strncat(path, "\\certs", size - strlen(path));
4119 wchar_t* wpath = utf8_to_wchar(path);
4120 if (MKDIR(wpath, 0700) && errno != EEXIST) {
4121 free_wchar(wpath);
4122 #else
4123 strncat(path, "/certs", size - strlen(path));
4124 if (MKDIR(path, 0700) && errno != EEXIST) {
4125 #endif
4126 tQSL_Error = TQSL_SYSTEM_ERROR;
4127 tQSL_Errno = errno;
4128 tqslTrace("tqsl_make_cert_path", "Making path %s failed with %s", path, strerror(errno));
4129 return NULL;
4130 }
4131 #ifdef _WIN32
4132 free_wchar(wpath);
4133 strncat(path, "\\", size - strlen(path));
4134 #else
4135 strncat(path, "/", size - strlen(path));
4136 #endif
4137 strncat(path, filename, size - strlen(path));
4138 return path;
4139 }
4140
4141 static int
4142 tqsl_clean_call(const char *callsign, char *buf, int size) {
4143 if ((static_cast<int>(strlen(callsign))) > size-1) {
4144 tQSL_Error = TQSL_BUFFER_ERROR;
4145 return 1;
4146 }
4147 const char *cp;
4148 for (cp = callsign; *cp; cp++) {
4149 if (!isdigit(*cp) && !isalpha(*cp))
4150 *buf = '_';
4151 else
4152 *buf = *cp;
4153 ++buf;
4154 }
4155 *buf = 0;
4156 return 0;
4157 }
4158
4159 static char *
4160 tqsl_make_key_path(const char *callsign, char *path, int size) {
4161 char fixcall[256];
4162
4163 tqsl_clean_call(callsign, fixcall, sizeof fixcall);
4164 strncpy(path, tQSL_BaseDir, size);
4165 #ifdef _WIN32
4166 strncat(path, "\\keys", size - strlen(path));
4167 wchar_t* wpath = utf8_to_wchar(path);
4168 if (MKDIR(wpath, 0700) && errno != EEXIST) {
4169 free_wchar(wpath);
4170 #else
4171 strncat(path, "/keys", size - strlen(path));
4172 if (MKDIR(path, 0700) && errno != EEXIST) {
4173 #endif
4174 strncpy(tQSL_ErrorFile, path, sizeof tQSL_ErrorFile);
4175 tQSL_Error = TQSL_SYSTEM_ERROR;
4176 tQSL_Errno = errno;
4177 tqslTrace("tqsl_make_key_path", "Making path %s failed with %s", path, strerror(errno));
4178 return 0;
4179 }
4180 #ifdef _WIN32
4181 free(wpath);
4182 strncat(path, "\\", size - strlen(path));
4183 #else
4184 strncat(path, "/", size - strlen(path));
4185 #endif
4186 strncat(path, fixcall, size - strlen(path));
4187 return path;
4188 }
4189
4190 static char *
4191 tqsl_make_backup_path(const char *callsign, char *path, int size) {
4192 char fixcall[256];
4193
4194 tqsl_clean_call(callsign, fixcall, sizeof fixcall);
4195 strncpy(path, tQSL_BaseDir, size);
4196 #ifdef _WIN32
4197 strncat(path, "\\certtrash", size - strlen(path));
4198 wchar_t* wpath = utf8_to_wchar(path);
4199 if (MKDIR(wpath, 0700) && errno != EEXIST) {
4200 free_wchar(wpath);
4201 #else
4202 strncat(path, "/certtrash", size - strlen(path));
4203 if (MKDIR(path, 0700) && errno != EEXIST) {
4204 #endif
4205 strncpy(tQSL_ErrorFile, path, sizeof tQSL_ErrorFile);
4206 tQSL_Error = TQSL_SYSTEM_ERROR;
4207 tQSL_Errno = errno;
4208 tqslTrace("tqsl_make_backup_path", "Making path %s failed with %s", path, strerror(errno));
4209 return 0;
4210 }
4211 #ifdef _WIN32
4212 free(wpath);
4213 strncat(path, "\\", size - strlen(path));
4214 #else
4215 strncat(path, "/", size - strlen(path));
4216 #endif
4217 strncat(path, fixcall, size - strlen(path));
4218 return path;
4219 }
4220
4221 static int
4222 tqsl_handle_root_cert(const char *pem, X509 *x, int (*cb)(int, const char *, void *), void *userdata) {
4223 const char *cp;
4224
4225 /* Verify self-signature on the root certificate */
4226 if ((cp = tqsl_ssl_verify_cert(x, NULL, NULL, 0, &tqsl_self_signed_is_ok)) != NULL) {
4227 strncpy(tQSL_CustomError, cp, sizeof tQSL_CustomError);
4228 tQSL_Error = TQSL_CUSTOM_ERROR;
4229 tqslTrace("tqsl_handle_root_cert", "sig verify err %s", tQSL_CustomError);
4230 return 1;
4231 }
4232 return tqsl_store_cert(pem, x, "root", TQSL_CERT_CB_ROOT, false, cb, userdata);
4233 }
4234
4235 static int
4236 tqsl_ssl_error_is_nofile() {
4237 unsigned long l = ERR_peek_error();
4238 if (tQSL_Error == TQSL_OPENSSL_ERROR &&
4239 ERR_GET_LIB(l) == ERR_LIB_SYS && ERR_GET_FUNC(l) == SYS_F_FOPEN)
4240 return 1;
4241 if (tQSL_Error == TQSL_SYSTEM_ERROR && tQSL_Errno == ENOENT)
4242 return 1;
4243 return 0;
4244 }
4245
4246 static int
4247 tqsl_handle_ca_cert(const char *pem, X509 *x, int (*cb)(int, const char *, void *), void *userdata) {
4248 STACK_OF(X509) *root_sk;
4249 char rootpath[256];
4250 const char *cp;
4251
4252 tqsl_make_cert_path("root", rootpath, sizeof rootpath);
4253 if ((root_sk = tqsl_ssl_load_certs_from_file(rootpath)) == NULL) {
4254 if (!tqsl_ssl_error_is_nofile()) {
4255 tqslTrace("tqsl_handle_ca_cert", "error not nofile - %d", errno);
4256 return 1;
4257 }
4258 }
4259 cp = tqsl_ssl_verify_cert(x, NULL, root_sk, 0, &tqsl_expired_is_ok);
4260 sk_X509_free(root_sk);
4261 if (cp) {
4262 strncpy(tQSL_CustomError, cp, sizeof tQSL_CustomError);
4263 tQSL_Error = TQSL_CUSTOM_ERROR;
4264 tqslTrace("tqsl_handle_ca_cert", "verify error %s", tQSL_CustomError);
4265 return 1;
4266 }
4267 return tqsl_store_cert(pem, x, "authorities", TQSL_CERT_CB_CA, false, cb, userdata);
4268 }
4269
4270 static int
4271 tqsl_handle_user_cert(const char *cpem, X509 *x, int (*cb)(int, const char *, void *), void *userdata) {
4272 STACK_OF(X509) *root_sk, *ca_sk;
4273 char rootpath[256], capath[256];
4274 char pem[sizeof tqsl_static_buf];
4275 const char *cp;
4276
4277 strncpy(pem, cpem, sizeof pem);
4278 /* Match the public key in the supplied certificate with a
4279 * private key in the key store.
4280 */
4281 if (tqsl_find_matching_key(x, NULL, NULL, "", NULL, NULL)) {
4282 if (tQSL_Error != TQSL_PASSWORD_ERROR) {
4283 tqslTrace("tqsl_handle_user_cert", "match error %s", tqsl_openssl_error());
4284 return 1;
4285 }
4286 tQSL_Error = TQSL_NO_ERROR; /* clear error */
4287 }
4288
4289 /* Check the chain of authority back to a trusted root */
4290 tqsl_make_cert_path("root", rootpath, sizeof rootpath);
4291 if ((root_sk = tqsl_ssl_load_certs_from_file(rootpath)) == NULL) {
4292 if (!tqsl_ssl_error_is_nofile()) {
4293 tqslTrace("tqsl_handle_user_cert", "Error loading certs %s", tqsl_openssl_error());
4294 return 1;
4295 }
4296 }
4297 tqsl_make_cert_path("authorities", capath, sizeof capath);
4298 if ((ca_sk = tqsl_ssl_load_certs_from_file(capath)) == NULL) {
4299 if (!tqsl_ssl_error_is_nofile()) {
4300 sk_X509_free(root_sk);
4301 tqslTrace("tqsl_handle_user_cert", "Error loading authorities %s", tqsl_openssl_error());
4302 return 1;
4303 }
4304 }
4305 cp = tqsl_ssl_verify_cert(x, ca_sk, root_sk, 0, &tqsl_expired_is_ok);
4306 sk_X509_free(ca_sk);
4307 sk_X509_free(root_sk);
4308 if (cp) {
4309 strncpy(tQSL_CustomError, cp, sizeof tQSL_CustomError);
4310 tQSL_Error = TQSL_CUSTOM_ERROR;
4311 tqslTrace("tqsl_handle_user_cert", "verify error %s", cp);
4312 return 1;
4313 }
4314 return tqsl_store_cert(pem, x, "user", TQSL_CERT_CB_USER, false, cb, userdata);
4315 }
4316
4317 CLIENT_STATIC int
4318 tqsl_store_cert(const char *pem, X509 *cert, const char *certfile, int type, bool force,
4319 int (*cb)(int, const char *, void *), void *userdata) {
4320 STACK_OF(X509) *sk;
4321 char path[256];
4322 char issuer[256];
4323 char name[256];
4324 char value[256];
4325 FILE *out;
4326 BIGNUM *bserial, *oldserial;
4327 string subjid, msg, callsign;
4328 TQSL_X509_NAME_ITEM item;
4329 int len, rval;
4330 tQSL_Date newExpires;
4331 string stype = "Unknown";
4332 const ASN1_TIME *tm;
4333
4334 if (type == TQSL_CERT_CB_ROOT) {
4335 stype = "Trusted Root Authority";
4336 } else if (type == TQSL_CERT_CB_CA) {
4337 stype = "Certificate Authority";
4338 } else if (type == TQSL_CERT_CB_USER) {
4339 stype = "Callsign";
4340 // Invalidate the cached user certs
4341 if (xcerts != NULL) {
4342 sk_X509_free(xcerts);
4343 xcerts = NULL;
4344 }
4345 }
4346
4347 tqsl_make_cert_path(certfile, path, sizeof path);
4348 item.name_buf = name;
4349 item.name_buf_size = sizeof name;
4350 item.value_buf = value;
4351 item.value_buf_size = sizeof value;
4352 if (tqsl_cert_get_subject_name_entry(cert, "AROcallsign", &item)) {
4353 // Subject contains a call sign (probably a user cert)
4354 callsign = value;
4355 strncpy(ImportCall, callsign.c_str(), sizeof(tQSL_ImportCall));
4356 tQSL_ImportSerial = ASN1_INTEGER_get(X509_get_serialNumber(cert));
4357 subjid = string(" ") + value;
4358 tm = X509_get_notAfter(cert);
4359 if (tm) {
4360 tqsl_get_asn1_date(tm, &newExpires);
4361 } else {
4362 newExpires.year = 9999;
4363 newExpires.month = 1;
4364 newExpires.day = 1;
4365 }
4366 if (tqsl_cert_get_subject_name_entry(cert, "commonName", &item))
4367 subjid += string(" (") + value + ")";
4368 len = sizeof value-1;
4369 if (!tqsl_get_cert_ext(cert, "dxccEntity", (unsigned char *)value, &len, NULL)) {
4370 value[len] = 0;
4371 subjid += string(" DXCC = ") + value;
4372 }
4373 } else if (tqsl_cert_get_subject_name_entry(cert, "organizationName", &item)) {
4374 // Subject contains an organization (probably a CA or root CA cert)
4375 subjid = string(" ") + value;
4376 if (tqsl_cert_get_subject_name_entry(cert, "organizationalUnitName", &item))
4377 subjid += string(" ") + value;
4378 }
4379 if (subjid == "") {
4380 // If haven't found a displayable subject name we undertand, use the raw DN
4381 X509_NAME_oneline(X509_get_subject_name(cert), issuer, sizeof issuer);
4382 subjid = string(" ") + issuer;
4383 }
4384
4385 X509_NAME_oneline(X509_get_issuer_name(cert), issuer, sizeof issuer);
4386
4387 /* Check for dupes */
4388 if ((sk = tqsl_ssl_load_certs_from_file(path)) == NULL) {
4389 if (!tqsl_ssl_error_is_nofile()) {
4390 tqslTrace("tqsl_store_cert", "unexpected openssl err %s", tqsl_openssl_error());
4391 return 1; /* Unexpected OpenSSL error */
4392 }
4393 }
4394 /* Check each certificate */
4395 if (sk != NULL) {
4396 int i, n;
4397 tQSL_Date expires;
4398 bserial = BN_new();
4399 ASN1_INTEGER_to_BN(X509_get_serialNumber(cert), bserial);
4400
4401 n = sk_X509_num(sk);
4402 for (i = 0; i < n; i++) {
4403 char buf[256];
4404 X509 *x;
4405 const char *cp;
4406
4407 x = sk_X509_value(sk, i);
4408 cp = X509_NAME_oneline(X509_get_issuer_name(x), buf, sizeof buf);
4409 if (cp != NULL && !strcmp(cp, issuer)) {
4410 oldserial = BN_new();
4411 ASN1_INTEGER_to_BN(X509_get_serialNumber(x), oldserial);
4412 int result = BN_ucmp(bserial, oldserial);
4413 BN_free(oldserial);
4414 if (result == 0)
4415 break; /* We have a match */
4416 }
4417
4418 if (!force && type == TQSL_CERT_CB_USER) { // Don't check for newer certs on restore
4419 item.name_buf = name;
4420 item.name_buf_size = sizeof name;
4421 item.value_buf = value;
4422 item.value_buf_size = sizeof value;
4423 if (tqsl_cert_get_subject_name_entry(x, "AROcallsign", &item)) {
4424 if (value == callsign) {
4425 /*
4426 * If it's another cert for
4427 * this call, is it older?
4428 */
4429 tm = X509_get_notAfter(x);
4430 if (tm) {
4431 tqsl_get_asn1_date(tm, &expires);
4432 } else {
4433 expires.year = 0;
4434 expires.month = 0;
4435 expires.day = 0;
4436 }
4437 if (tqsl_compareDates(&newExpires, &expires) < 0) {
4438 tQSL_Error = TQSL_CUSTOM_ERROR;
4439 strncpy(tQSL_CustomError, "A newer certificate for this callsign is already installed",
4440 sizeof tQSL_CustomError);
4441 tqslTrace("tqsl_load_cert", tQSL_CustomError);
4442 BN_free(bserial);
4443 sk_X509_free(sk);
4444 return 1;
4445 }
4446 }
4447 }
4448 }
4449 }
4450 BN_free(bserial);
4451 sk_X509_free(sk);
4452 if (i < n) { /* Have a match -- cert is already in the file */
4453 if (cb != NULL) {
4454 int rval;
4455 string msg = "Duplicate " + stype + " certificate: " + subjid;
4456
4457 rval = (*cb)(TQSL_CERT_CB_RESULT | type | TQSL_CERT_CB_DUPLICATE, msg.c_str(), userdata);
4458 if (rval) {
4459 tQSL_Error = TQSL_CUSTOM_ERROR;
4460 strncpy(tQSL_CustomError, "Duplicate Callsign certificate",
4461 sizeof tQSL_CustomError);
4462 tqslTrace("tqsl_load_cert", tQSL_CustomError);
4463 return 1;
4464 }
4465 }
4466 if (tQSL_Error == 0) {
4467 tQSL_Error = TQSL_CERT_ERROR;
4468 }
4469 return 1;
4470 }
4471 }
4472 /* Cert is not a duplicate. Append it to the certificate file */
4473 if (cb != NULL) {
4474 msg = "Adding " + stype + " Certificate for: " + subjid;
4475
4476 tqslTrace("tqsl_load_cert", msg.c_str());
4477 rval = (*cb)(TQSL_CERT_CB_MILESTONE | type | TQSL_CERT_CB_PROMPT, msg.c_str(), userdata);
4478 if (rval) {
4479 tqslTrace("tqsl_load_cert", "operator aborted");
4480 tQSL_Error = TQSL_OPERATOR_ABORT;
4481 return 1;
4482 }
4483 }
4484 #ifdef _WIN32
4485 wchar_t* wpath = utf8_to_wchar(path);
4486 if ((out = _wfopen(wpath, L"a")) == NULL) {
4487 free_wchar(wpath);
4488 #else
4489 if ((out = fopen(path, "a")) == NULL) {
4490 #endif
4491 strncpy(tQSL_ErrorFile, path, sizeof tQSL_ErrorFile);
4492 tQSL_Error = TQSL_SYSTEM_ERROR;
4493 tQSL_Errno = errno;
4494 tqslTrace("tqsl_load_cert", "opening file err %s", strerror(errno));
4495 return 1;
4496 }
4497 #ifdef _WIN32
4498 free(wpath);
4499 #endif
4500 // Make sure there's always a newline between certs
4501 size_t pemlen = strlen(pem);
4502 if (fwrite("\n", 1, 1, out) != 1 || fwrite(pem, 1, pemlen, out) != pemlen) {
4503 strncpy(tQSL_ErrorFile, certfile, sizeof tQSL_ErrorFile);
4504 tQSL_Error = TQSL_SYSTEM_ERROR;
4505 tQSL_Errno = errno;
4506 tqslTrace("tqsl_load_cert", "writing file err %s", strerror(errno));
4507 return 1;
4508 }
4509 if (fclose(out) == EOF) {
4510 strncpy(tQSL_ErrorFile, certfile, sizeof tQSL_ErrorFile);
4511 tQSL_Error = TQSL_SYSTEM_ERROR;
4512 tQSL_Errno = errno;
4513 tqslTrace("tqsl_load_cert", "writing file err %s", strerror(errno));
4514 return 1;
4515 }
4516 msg = "Loaded: " + subjid;
4517 if (cb)
4518 rval = (*cb)(TQSL_CERT_CB_RESULT | type | TQSL_CERT_CB_LOADED, msg.c_str(), userdata);
4519 else
4520 rval = 0;
4521 if (rval) {
4522 tQSL_Error = TQSL_OPERATOR_ABORT;
4523 return 1;
4524 }
4525 strncpy(tQSL_ImportCall, ImportCall, sizeof tQSL_ImportCall);
4526 return 0;
4527 }
4528
4529 static int pw_aborted;
4530
4531 static int
4532 fixed_password_callback(char *buf, int bufsiz, int verify, void *userdata) {
4533 pw_aborted = 0;
4534 if (userdata != NULL)
4535 strncpy(buf, reinterpret_cast<char *>(userdata), bufsiz);
4536 else
4537 buf[0] = 0;
4538 return strlen(buf);
4539 }
4540
4541 static void *prompt_userdata;
4542
4543 static int
4544 prompted_password_callback(char *buf, int bufsiz, int verify, void *userfunc) {
4545 pw_aborted = 0;
4546 if (userfunc != NULL) {
4547 int (*cb)(char *, int, void *) = (int (*)(char *, int, void *))userfunc;
4548 if ((*cb)(buf, bufsiz, prompt_userdata)) {
4549 pw_aborted = 1;
4550 return 0;
4551 }
4552 } else {
4553 buf[0] = 0;
4554 }
4555 return strlen(buf);
4556 }
4557
4558 static tQSL_ADIF keyf_adif = 0;
4559
4560 static int
4561 tqsl_open_key_file(const char *path) {
4562 if (keyf_adif)
4563 tqsl_endADIF(&keyf_adif);
4564 return tqsl_beginADIF(&keyf_adif, path);
4565 }
4566
4567 static int
4568 tqsl_read_key(map<string, string>& fields) {
4569 TQSL_ADIF_GET_FIELD_ERROR adif_status;
4570 tqsl_adifFieldResults field;
4571 static tqsl_adifFieldDefinitions adif_fields[] = {
4572 { "PUBLIC_KEY", "", TQSL_ADIF_RANGE_TYPE_NONE, 2000, 0, 0, NULL, NULL },
4573 { "PRIVATE_KEY", "", TQSL_ADIF_RANGE_TYPE_NONE, 2000, 0, 0, NULL, NULL },
4574 { "CALLSIGN", "", TQSL_ADIF_RANGE_TYPE_NONE, 2000, 0, 0, NULL, NULL },
4575 { "TQSL_CRQ_PROVIDER", "", TQSL_ADIF_RANGE_TYPE_NONE, 2000, 0, 0, NULL, NULL },
4576 { "TQSL_CRQ_PROVIDER_UNIT", "", TQSL_ADIF_RANGE_TYPE_NONE, 2000, 0, 0, NULL, NULL },
4577 { "TQSL_CRQ_ADDRESS1", "", TQSL_ADIF_RANGE_TYPE_NONE, 2000, 0, 0, NULL, NULL },
4578 { "TQSL_CRQ_ADDRESS2", "", TQSL_ADIF_RANGE_TYPE_NONE, 2000, 0, 0, NULL, NULL },
4579 { "TQSL_CRQ_CITY", "", TQSL_ADIF_RANGE_TYPE_NONE, 2000, 0, 0, NULL, NULL },
4580 { "TQSL_CRQ_STATE", "", TQSL_ADIF_RANGE_TYPE_NONE, 2000, 0, 0, NULL, NULL },
4581 { "TQSL_CRQ_POSTAL", "", TQSL_ADIF_RANGE_TYPE_NONE, 2000, 0, 0, NULL, NULL },
4582 { "TQSL_CRQ_COUNTRY", "", TQSL_ADIF_RANGE_TYPE_NONE, 2000, 0, 0, NULL, NULL },
4583 { "TQSL_CRQ_DXCC_ENTITY", "", TQSL_ADIF_RANGE_TYPE_NONE, 2000, 0, 0, NULL, NULL },
4584 { "TQSL_CRQ_QSO_NOT_BEFORE", "", TQSL_ADIF_RANGE_TYPE_NONE, 2000, 0, 0, NULL, NULL },
4585 { "TQSL_CRQ_QSO_NOT_AFTER", "", TQSL_ADIF_RANGE_TYPE_NONE, 2000, 0, 0, NULL, NULL },
4586 { "DELETED", "", TQSL_ADIF_RANGE_TYPE_NONE, 200, 0, 0, NULL, NULL },
4587 { "eor", "", TQSL_ADIF_RANGE_TYPE_NONE, 0, 0, 0, NULL, NULL },
4588 { "", "", TQSL_ADIF_RANGE_TYPE_NONE, 0, 0, 0, NULL, NULL },
4589 };
4590
4591 fields.clear();
4592 do {
4593 if (tqsl_getADIFField(keyf_adif, &field, &adif_status, adif_fields, notypes, &tqsl_static_alloc))
4594 return 1;
4595 if (adif_status == TQSL_ADIF_GET_FIELD_EOF)
4596 return 1;
4597 if (!strcasecmp(field.name, "eor"))
4598 return 0;
4599 if (adif_status == TQSL_ADIF_GET_FIELD_SUCCESS) {
4600 char *cp;
4601 for (cp = field.name; *cp; cp++)
4602 *cp = toupper(*cp);
4603 fields[field.name] = reinterpret_cast<char *>(field.data);
4604 }
4605 } while (adif_status == TQSL_ADIF_GET_FIELD_SUCCESS || adif_status == TQSL_ADIF_GET_FIELD_NO_NAME_MATCH);
4606 tQSL_Error = TQSL_ADIF_ERROR;
4607 return 1;
4608 }
4609
4610 static void
4611 tqsl_close_key_file(void) {
4612 tqsl_endADIF(&keyf_adif);
4613 }
4614
4615 static int
4616 tqsl_replace_key(const char *callsign, const char *path, map<string, string>& newfields, int (*cb)(int, const char *, void *), void *userdata) {
4617 char newpath[300];
4618 char savepath[300];
4619 #ifdef _WIN32
4620 wchar_t* wnewpath = NULL;
4621 #endif
4622 map<string, string> fields;
4623 vector< map<string, string> > records;
4624 vector< map<string, string> >::iterator it;
4625 vector<string>seen;
4626 EVP_PKEY *new_key = NULL, *key = NULL;
4627 BIO *bio = 0;
4628 FILE *out = 0;
4629 int rval = 1;
4630
4631 if ((bio = BIO_new_mem_buf(reinterpret_cast<void *>(const_cast<char *>(newfields["PUBLIC_KEY"].c_str())),
4632 newfields["PUBLIC_KEY"].length())) == NULL) {
4633 tqslTrace("tqsl_replace_key", "BIO_new_mem_buf err %s", tqsl_openssl_error());
4634 goto trk_end;
4635 }
4636 if ((new_key = PEM_read_bio_PUBKEY(bio, NULL, NULL, NULL)) == NULL) {
4637 tqslTrace("tqsl_replace_key", "PEM_read_bio_PUBKEY err %s", tqsl_openssl_error());
4638 goto trk_end;
4639 }
4640 BIO_free(bio);
4641 bio = 0;
4642 if (tqsl_open_key_file(path)) {
4643 if (tQSL_Error != TQSL_SYSTEM_ERROR || tQSL_Errno != ENOENT) {
4644 tqslTrace("tqsl_replace_key", "error opening key file %s: %s", path, strerror(tQSL_Errno));
4645 return 1;
4646 }
4647 tQSL_Error = TQSL_NO_ERROR;
4648 }
4649 while (tqsl_read_key(fields) == 0) {
4650 if ((bio = BIO_new_mem_buf(reinterpret_cast<void *>(const_cast<char *>(fields["PUBLIC_KEY"].c_str())),
4651 fields["PUBLIC_KEY"].length())) == NULL) {
4652 tqslTrace("tqsl_replace_key", "BIO_new_mem_buf error %s", tqsl_openssl_error());
4653 goto trk_end;
4654 }
4655 if ((key = PEM_read_bio_PUBKEY(bio, NULL, NULL, NULL)) == NULL) {
4656 tqslTrace("tqsl_replace_key", "Pem_read_bio_rsa_pubkey error %s", tqsl_openssl_error());
4657 goto trk_end;
4658 }
4659 BIO_free(bio);
4660 bio = NULL;
4661 if (EVP_PKEY_cmp(key, new_key) == 1) {
4662 fields["DELETED"] = "True";
4663 }
4664 bool seenbefore = false;
4665 for (size_t i = 0; i < seen.size(); i++) {
4666 if (seen[i] == fields["PUBLIC_KEY"]) {
4667 seenbefore = true;
4668 break;
4669 }
4670 }
4671 if (!seenbefore) {
4672 records.push_back(fields);
4673 seen.push_back(fields["PUBLIC_KEY"]);
4674 }
4675 }
4676 tqsl_close_key_file();
4677 if (newfields["PRIVATE_KEY"] != "")
4678 records.push_back(newfields);
4679 strncpy(newpath, path, sizeof newpath);
4680 strncat(newpath, ".new", sizeof newpath - strlen(newpath)-1);
4681 strncpy(savepath, path, sizeof savepath);
4682 strncat(savepath, ".save", sizeof savepath - strlen(savepath)-1);
4683 #ifdef _WIN32
4684 wnewpath = utf8_to_wchar(newpath);
4685 if ((out = _wfopen(wnewpath, TQSL_OPEN_WRITE)) == NULL) {
4686 free_wchar(wnewpath);
4687 #else
4688 if ((out = fopen(newpath, TQSL_OPEN_WRITE)) == NULL) {
4689 #endif
4690 tQSL_Error = TQSL_SYSTEM_ERROR;
4691 tQSL_Errno = errno;
4692 tqslTrace("tqsl_replace_key", "open file %s: %s", newpath, strerror(tQSL_Errno));
4693 goto trk_end;
4694 }
4695 for (it = records.begin(); it != records.end(); it++) {
4696 map<string, string>::iterator mit;
4697 for (mit = it->begin(); mit != it->end(); mit++) {
4698 if (tqsl_write_adif_field(out, mit->first.c_str(), 0, (const unsigned char *)mit->second.c_str(), -1)) {
4699 tqslTrace("tqsl_replace_key", "error writing %s", strerror(tQSL_Errno));
4700 #ifdef _WIN32
4701 free_wchar(wnewpath);
4702 #endif
4703 goto trk_end;
4704 }
4705 }
4706 tqsl_write_adif_field(out, "eor", 0, NULL, 0);
4707 }
4708 if (fclose(out) == EOF) {
4709 tQSL_Error = TQSL_SYSTEM_ERROR;
4710 tQSL_Errno = errno;
4711 tqslTrace("tqsl_replace_key", "error closing %s", strerror(tQSL_Errno));
4712 #ifdef _WIN32
4713 free_wchar(wnewpath);
4714 #endif
4715 goto trk_end;
4716 }
4717 out = 0;
4718
4719 /* Output file looks okay. Replace the old file with the new one. */
4720 #ifdef _WIN32
4721 wchar_t* wsavepath = utf8_to_wchar(savepath);
4722 if (_wunlink(wsavepath) && errno != ENOENT) {
4723 free_wchar(wsavepath);
4724 free_wchar(wnewpath);
4725 #else
4726 if (unlink(savepath) && errno != ENOENT) {
4727 #endif
4728 tQSL_Error = TQSL_SYSTEM_ERROR;
4729 tQSL_Errno = errno;
4730 tqslTrace("tqsl_replace_key", "unlink file %s: %s", savepath, strerror(tQSL_Errno));
4731 goto trk_end;
4732 }
4733 #ifdef _WIN32
4734 wchar_t* wpath = utf8_to_wchar(path);
4735 if (_wrename(wpath, wsavepath) && errno != ENOENT) {
4736 free_wchar(wpath);
4737 free_wchar(wsavepath);
4738 free_wchar(wnewpath);
4739 #else
4740 if (rename(path, savepath) && errno != ENOENT) {
4741 #endif
4742 tQSL_Error = TQSL_SYSTEM_ERROR;
4743 tQSL_Errno = errno;
4744 tqslTrace("tqsl_replace_key", "rename file %s->%s: %s", path, savepath, strerror(tQSL_Errno));
4745 goto trk_end;
4746 }
4747 #ifdef _WIN32
4748 if (_wrename(wnewpath, wpath)) {
4749 free_wchar(wnewpath);
4750 free_wchar(wpath);
4751 free_wchar(wsavepath);
4752 #else
4753 if (rename(newpath, path)) {
4754 #endif
4755 tQSL_Error = TQSL_SYSTEM_ERROR;
4756 tQSL_Errno = errno;
4757 tqslTrace("tqsl_replace_key", "rename file %s->%s: %s", newpath, path, strerror(tQSL_Errno));
4758 goto trk_end;
4759 }
4760 #ifdef _WIN32
4761 free_wchar(wnewpath);
4762 free_wchar(wpath);
4763 free_wchar(wsavepath);
4764 #endif
4765
4766 tqslTrace("tqsl_replace_key", "loaded private key for: %s", callsign);
4767 if (cb) {
4768 string msg = string("Loaded private key for: ") + callsign;
4769 (*cb)(TQSL_CERT_CB_RESULT + TQSL_CERT_CB_PKEY + TQSL_CERT_CB_LOADED, msg.c_str(), userdata);
4770 }
4771 rval = 0;
4772 trk_end:
4773 tqsl_close_key_file();
4774 if (out)
4775 fclose(out);
4776 if (new_key)
4777 EVP_PKEY_free(new_key);
4778 if (key)
4779 EVP_PKEY_free(key);
4780 if (bio)
4781 BIO_free(bio);
4782 return rval;
4783 }
4784
4785 static int
4786 tqsl_unlock_key(const char *pem, EVP_PKEY **keyp, const char *password, int (*cb)(char *, int, void *), void *userdata) {
4787 RSA *prsa = NULL;
4788 BIO *bio;
4789 int (*ssl_cb)(char *, int, int, void *) = NULL;
4790 void *cb_user = NULL;
4791 long e;
4792 int rval = 1;
4793
4794 if ((bio = BIO_new_mem_buf(reinterpret_cast<void *>(const_cast<char *>(pem)), strlen(pem))) == NULL) {
4795 tqslTrace("tqsl_unlock_key", "BIO_new_mem_buf err %s", tqsl_openssl_error());
4796 goto err;
4797 }
4798 if (password != NULL) {
4799 ssl_cb = &fixed_password_callback;
4800 cb_user = reinterpret_cast<void *>(const_cast<char *>(password));
4801 } else if (cb != NULL) {
4802 prompt_userdata = userdata;
4803 ssl_cb = &prompted_password_callback;
4804 cb_user = reinterpret_cast<void *>(cb);
4805 }
4806 if ((prsa = PEM_read_bio_RSAPrivateKey(bio, NULL, ssl_cb, cb_user)) == NULL) {
4807 tqslTrace("tqsl_unlock_key", "PEM_read_bio_RSAPrivateKey err %s", tqsl_openssl_error());
4808 goto err;
4809 }
4810 if (keyp != NULL) {
4811 if ((*keyp = EVP_PKEY_new()) == NULL)
4812 goto err;
4813 EVP_PKEY_assign_RSA(*keyp, prsa);
4814 prsa = NULL;
4815 }
4816 rval = 0;
4817 goto end;
4818 err:
4819 e = ERR_peek_error();
4820 if ((ERR_GET_LIB(e) == ERR_LIB_EVP && ERR_GET_REASON(e) == EVP_R_BAD_DECRYPT)
4821 || (ERR_GET_LIB(e) == ERR_LIB_PEM && ERR_GET_REASON(e) == PEM_R_BAD_PASSWORD_READ)
4822 || (ERR_GET_LIB(e) == ERR_LIB_PKCS12 && ERR_GET_REASON(e) == PKCS12_R_PKCS12_CIPHERFINAL_ERROR)) {
4823 tqsl_getErrorString(); /* clear error */
4824 tQSL_Error = pw_aborted ? TQSL_OPERATOR_ABORT : TQSL_PASSWORD_ERROR;
4825 ERR_clear_error();
4826 } else {
4827 tQSL_Error = TQSL_OPENSSL_ERROR;
4828 }
4829 tqslTrace("tqsl_unlock_key", "Key read error %d", tQSL_Error);
4830 end:
4831 if (prsa != NULL)
4832 RSA_free(prsa);
4833 if (bio != NULL)
4834 BIO_free(bio);
4835 return rval;
4836 }
4837
4838 static int
4839 tqsl_find_matching_key(X509 *cert, EVP_PKEY **keyp, TQSL_CERT_REQ **crq, const char *password, int (*cb)(char *, int, void *), void *userdata) {
4840 char path[256];
4841 char aro[256];
4842 TQSL_X509_NAME_ITEM item = { path, sizeof path, aro, sizeof aro };
4843 EVP_PKEY *cert_key = NULL;
4844 EVP_PKEY *curkey = NULL;
4845 int rval = 0;
4846 int match = 0;
4847 int deleted = 0;
4848 BIO *bio = NULL;
4849 map<string, string> fields;
4850
4851 if (keyp != NULL)
4852 *keyp = NULL;
4853
4854 if (!tqsl_cert_get_subject_name_entry(cert, "AROcallsign", &item)) {
4855 tqslTrace("tqsl_find_matching_key", "get subj name err %d", tQSL_Error);
4856 return 1;
4857 }
4858 tQSL_ImportSerial = ASN1_INTEGER_get(X509_get_serialNumber(cert));
4859 if (!tqsl_make_key_path(aro, path, sizeof path)) {
4860 tqslTrace("tqsl_find_matching_key", "key path err %d", tQSL_Error);
4861 rval = 1;
4862 goto end_nokey;
4863 }
4864 strncpy(ImportCall, aro, sizeof ImportCall);
4865 if (tqsl_open_key_file(path)) {
4866 /* Friendly error for file not found */
4867 if (tQSL_Error == TQSL_SYSTEM_ERROR) {
4868 if (tQSL_Errno == ENOENT) {
4869 snprintf(tQSL_CustomError, sizeof tQSL_CustomError,
4870 "You can only open this callsign certificate by running TQSL on the computer where you created the certificate request for %s.", aro);
4871 } else {
4872 snprintf(tQSL_CustomError, sizeof tQSL_CustomError,
4873 "Can't open %s: %s\nThis file is needed to open this callsign certificate.",
4874 aro, strerror(tQSL_Errno));
4875 }
4876 tQSL_Error = TQSL_CUSTOM_ERROR;
4877 tqslTrace("tqsl_find_matching_key", "opening file path err %s", tQSL_CustomError);
4878 }
4879 return 1;
4880 }
4881 if ((cert_key = X509_get_pubkey(cert)) == NULL) {
4882 tqslTrace("tqsl_find_matching_key", "error getting public key %s", tqsl_openssl_error());
4883 goto err;
4884 }
4885 if (crq != NULL) {
4886 if (*crq != NULL)
4887 tqsl_free_cert_req(*crq, 0);
4888 *crq = reinterpret_cast<TQSL_CERT_REQ *>(tqsl_calloc(1, sizeof(TQSL_CERT_REQ)));
4889 }
4890 while (!tqsl_read_key(fields)) {
4891 /* Compare the keys */
4892 if ((bio = BIO_new_mem_buf(reinterpret_cast<void *>(const_cast<char *>(fields["PUBLIC_KEY"].c_str())),
4893 fields["PUBLIC_KEY"].length())) == NULL) {
4894 tqslTrace("tqsl_find_matching_key", "BIO_new_mem_buf err %s", tqsl_openssl_error());
4895 goto err;
4896 }
4897 if ((curkey = PEM_read_bio_PUBKEY(bio, NULL, NULL, NULL)) == NULL) {
4898 tqslTrace("tqsl_find_matching_key", "PEM_read_bio_RSA_PUBKEY err %s", tqsl_openssl_error());
4899 goto err;
4900 }
4901 BIO_free(bio);
4902 bio = NULL;
4903 if (EVP_PKEY_cmp(curkey, cert_key) == 1) {
4904 if (fields["DELETED"] == "True") {
4905 deleted = 1;
4906 }
4907 match = 1;
4908 }
4909 if (match) {
4910 /* We have a winner */
4911 if (tqsl_unlock_key(fields["PRIVATE_KEY"].c_str(), keyp, password, cb, userdata)) {
4912 tqslTrace("tqsl_find_matching_key", "tqsl_unlock_key err %d", tQSL_Error);
4913 rval = 1;
4914 goto end;
4915 }
4916 if (crq != NULL) {
4917 tQSL_Error = TQSL_BUFFER_ERROR;
4918 if (!safe_strncpy((*crq)->providerName, fields["TQSL_CRQ_PROVIDER"].c_str(), sizeof (*crq)->providerName))
4919 goto end;
4920 if (!safe_strncpy((*crq)->providerUnit, fields["TQSL_CRQ_PROVIDER_UNIT"].c_str(), sizeof (*crq)->providerUnit))
4921 goto end;
4922 if (!safe_strncpy((*crq)->address1, fields["TQSL_CRQ_ADDRESS1"].c_str(), sizeof (*crq)->address1))
4923 goto end;
4924 if (!safe_strncpy((*crq)->address2, fields["TQSL_CRQ_ADDRESS2"].c_str(), sizeof (*crq)->address2))
4925 goto end;
4926 if (!safe_strncpy((*crq)->city, fields["TQSL_CRQ_CITY"].c_str(), sizeof (*crq)->city))
4927 goto end;
4928 if (!safe_strncpy((*crq)->state, fields["TQSL_CRQ_STATE"].c_str(), sizeof (*crq)->state))
4929 goto end;
4930 if (!safe_strncpy((*crq)->postalCode, fields["TQSL_CRQ_POSTAL"].c_str(), sizeof (*crq)->postalCode))
4931 goto end;
4932 if (!safe_strncpy((*crq)->country, fields["TQSL_CRQ_COUNTRY"].c_str(), sizeof (*crq)->country))
4933 goto end;
4934 tQSL_Error = 0;
4935 }
4936 rval = 0;
4937 break;
4938 }
4939 }
4940 if (match)
4941 goto end;
4942 tqslTrace("tqsl_find_matching_key", "No matching private key found");
4943 rval = 1;
4944 tQSL_Error = TQSL_CERT_NOT_FOUND;
4945 strncpy(tQSL_ImportCall, ImportCall, sizeof tQSL_ImportCall);
4946 goto end;
4947 err:
4948 rval = 1;
4949 tQSL_Error = TQSL_OPENSSL_ERROR;
4950 end:
4951 tqsl_close_key_file();
4952 if (deleted) {
4953 int savedErr = tQSL_Error;
4954 tqsl_clear_deleted(aro, path, cert_key);
4955 tQSL_Error = savedErr;
4956 }
4957 end_nokey:
4958 if (curkey != NULL)
4959 EVP_PKEY_free(curkey);
4960 if (bio != NULL)
4961 BIO_free(bio);
4962 if (cert_key != NULL)
4963 EVP_PKEY_free(cert_key);
4964 // if (in != NULL)
4965 // fclose(in);
4966 if (rval == 0) {
4967 strncpy(tQSL_ImportCall, ImportCall, sizeof tQSL_ImportCall);
4968 }
4969 return rval;
4970 }
4971
4972 static int
4973 tqsl_make_key_list(vector< map<string, string> > & keys) {
4974 keys.clear();
4975
4976 string path = tQSL_BaseDir;
4977 #ifdef _WIN32
4978 path += "\\keys";
4979 wchar_t* wpath = utf8_to_wchar(path.c_str());
4980 MKDIR(wpath, 0700);
4981 #else
4982 path += "/keys";
4983 MKDIR(path.c_str(), 0700);
4984 #endif
4985
4986 #ifdef _WIN32
4987 WDIR *dir = wopendir(wpath);
4988 free_wchar(wpath);
4989 #else
4990 DIR *dir = opendir(path.c_str());
4991 #endif
4992 if (dir == NULL) {
4993 tQSL_Error = TQSL_SYSTEM_ERROR;
4994 tQSL_Errno = errno;
4995 tqslTrace("tqsl_make_key_list", "Opendir %s error %s", path.c_str(), strerror(errno));
4996 return 1;
4997 }
4998 #ifdef _WIN32
4999 struct wdirent *ent;
5000 #else
5001 struct dirent *ent;
5002 #endif
5003 int rval = 0;
5004 int savedError = 0;
5005 int savedErrno = 0;
5006 char *savedFile = NULL;
5007
5008 #ifdef _WIN32
5009 while ((ent = wreaddir(dir)) != NULL) {
5010 if (ent->d_name[0] == '.')
5011 continue;
5012 if (wcsstr(ent->d_name, L".save") || wcsstr(ent->d_name, L".new"))
5013 continue;
5014 char dname[TQSL_MAX_PATH_LEN];
5015 wcstombs(dname, ent->d_name, TQSL_MAX_PATH_LEN);
5016 string filename = path + "\\" + dname;
5017 #else
5018 while ((ent = readdir(dir)) != NULL) {
5019 if (ent->d_name[0] == '.')
5020 continue;
5021 if (strstr(ent->d_name, ".save") || strstr(ent->d_name, ".new"))
5022 continue;
5023 string filename = path + "/" + ent->d_name;
5024 #endif
5025 char fixcall[256];
5026 #ifdef _WIN32
5027 struct _stat32 s;
5028 wchar_t* wfilename = utf8_to_wchar(filename.c_str());
5029 if (_wstat32(wfilename, &s) == 0) {
5030 if (S_ISDIR(s.st_mode)) {
5031 free_wchar(wfilename);
5032 continue; // If it's a directory, skip it.
5033 }
5034 }
5035 #else
5036 struct stat s;
5037 if (stat(filename.c_str(), &s) == 0) {
5038 if (S_ISDIR(s.st_mode))
5039 continue; // If it's a directory, skip it.
5040 }
5041 #endif
5042 if (!tqsl_open_key_file(filename.c_str())) {
5043 map<string, string> fields;
5044 while (!tqsl_read_key(fields)) {
5045 if (fields["DELETED"] == "True")
5046 continue; // Skip this one
5047 if (tqsl_clean_call(fields["CALLSIGN"].c_str(), fixcall, sizeof fixcall)) {
5048 rval = 1;
5049 savedError = tQSL_Error;
5050 savedErrno = tQSL_Errno;
5051 if (savedFile)
5052 free(savedFile);
5053 savedFile = strdup(tQSL_ErrorFile);
5054 continue; // Keep looking for keys
5055 }
5056 #ifdef _WIN32
5057 wchar_t* wfixcall = utf8_to_wchar(fixcall);
5058 if (wcscmp(wfixcall, ent->d_name)) {
5059 free_wchar(wfixcall);
5060 #else
5061 if (strcasecmp(fixcall, ent->d_name)) {
5062 #endif
5063 continue;
5064 }
5065 keys.push_back(fields);
5066 }
5067 tqsl_close_key_file();
5068 } else {
5069 rval = 1; // Unable to open - remember that
5070 savedErrno = tQSL_Errno;
5071 savedError = tQSL_Error;
5072 if (savedFile)
5073 free(savedFile);
5074 savedFile = strdup(tQSL_ErrorFile);
5075 }
5076 }
5077 #ifdef _WIN32
5078 _wclosedir(dir);
5079 #else
5080 closedir(dir);
5081 #endif
5082 if (rval) {
5083 tQSL_Error = savedError;
5084 tQSL_Errno = savedErrno;
5085 if (savedFile) {
5086 strncpy(tQSL_ErrorFile, savedFile, sizeof tQSL_ErrorFile);
5087 free(savedFile);
5088 }
5089 tqslTrace("tqsl_make_key_list", "error %s %s", tQSL_ErrorFile, strerror(tQSL_Errno));
5090 }
5091 return rval;
5092 }
5093
5094 static int
5095 tqsl_get_cert_ext(X509 *cert, const char *ext, unsigned char *userbuf, int *buflen, int *crit) {
5096 int i, n, datasiz;
5097 X509_EXTENSION *xe;
5098 char buf[256];
5099 ASN1_OBJECT *obj;
5100 ASN1_OCTET_STRING *data;
5101
5102 if (tqsl_init())
5103 return 1;
5104 if (cert == NULL || ext == NULL || userbuf == NULL || buflen == NULL) {
5105 tqslTrace("tqsl_get_cert_ext", "arg error cert=0x%lx, ext=0x%lx userbuf=0x%lx, buflen=0x%lx crit=0x%lx", cert, ext, userbuf, buflen, crit);
5106 tQSL_Error = TQSL_ARGUMENT_ERROR;
5107 return 1;
5108 }
5109 n = X509_get_ext_count(cert);
5110 for (i = 0; i < n; i++) {
5111 xe = X509_get_ext(cert, i);
5112 if (xe == NULL) {
5113 tqslTrace("tqsl_get_cert_ext", "X509_get_ext error %s", tqsl_openssl_error());
5114 tQSL_Error = TQSL_OPENSSL_ERROR;
5115 return 1;
5116 }
5117 buf[0] = '\0';
5118 obj = X509_EXTENSION_get_object(xe);
5119 if (obj)
5120 OBJ_obj2txt(buf, sizeof buf, obj, 0);
5121 if (strcmp(buf, ext))
5122 continue;
5123 /* This is the desired extension */
5124 data = X509_EXTENSION_get_data(xe);
5125 if (data != NULL) {
5126 datasiz = ASN1_STRING_length(data);
5127 if (datasiz > *buflen-1) {
5128 tqslTrace("tqsl_get_cert_ext", "buffer len %d needed %d", *buflen, datasiz);
5129 tQSL_Error = TQSL_BUFFER_ERROR;
5130 return 1;
5131 }
5132 *buflen = datasiz;
5133 if (datasiz)
5134 memcpy(userbuf, ASN1_STRING_get0_data(data), datasiz);
5135 userbuf[datasiz] = '\0';
5136 }
5137 if (crit != NULL)
5138 *crit = X509_EXTENSION_get_critical(xe);
5139 return 0;
5140 }
5141 snprintf(tQSL_CustomError, sizeof tQSL_CustomError,
5142 "Certificate Extension not found: %s", ext);
5143 tQSL_Error = TQSL_CUSTOM_ERROR;
5144 if (strcmp(ext, "supercededCertificate"))
5145 tqslTrace("tqsl_get_cert_ext", "Err %s", tQSL_CustomError);
5146 return 1;
5147 }
5148
5149 CLIENT_STATIC int
5150 tqsl_get_asn1_date(const ASN1_TIME *tm, tQSL_Date *date) {
5151 char *v;
5152 int i;
5153
5154 i = tm->length;
5155 v = reinterpret_cast<char *>(tm->data);
5156
5157 if (i >= 14) {
5158 for (i = 0; i < 12; i++)
5159 if ((v[i] > '9') || (v[i] < '0')) goto err;
5160 date->year = (v[0]-'0')*1000+(v[1]-'0')*100 + (v[2]-'0')*10+(v[3]-'0');
5161 date->month = (v[4]-'0')*10+(v[5]-'0');
5162 if ((date->month > 12) || (date->month < 1)) goto err;
5163 date->day = (v[6]-'0')*10+(v[7]-'0');
5164 } else if (i < 12) {
5165 goto err;
5166 } else {
5167 for (i = 0; i < 10; i++)
5168 if ((v[i] > '9') || (v[i] < '0')) goto err;
5169 date->year = (v[0]-'0')*10+(v[1]-'0');
5170 if (date->year < 50) date->year+=100;
5171 date->year += 1900;
5172 date->month = (v[2]-'0')*10+(v[3]-'0');
5173 if ((date->month > 12) || (date->month < 1)) goto err;
5174 date->day = (v[4]-'0')*10+(v[5]-'0');
5175 }
5176 return 0;
5177
5178 err:
5179 tqslTrace("tqsl_get_asn1_date", "invalid date");
5180 tQSL_Error = TQSL_INVALID_DATE;
5181 return 1;
5182 }
5183
5184 static char *
5185 tqsl_sign_base64_data(tQSL_Cert cert, char *b64data) {
5186 int len;
5187 static unsigned char sig[256];
5188 int siglen = sizeof sig;
5189
5190 if (b64data && !strncmp(b64data, "-----", 5)) {
5191 b64data = strchr(b64data, '\n');
5192 if (b64data == NULL)
5193 return NULL;
5194 b64data++;
5195 }
5196 len = sizeof tqsl_static_buf;
5197 if (tqsl_decodeBase64(b64data, tqsl_static_buf, &len))
5198 return NULL;
5199 if (tqsl_signDataBlock(cert, tqsl_static_buf, len, sig, &siglen))
5200 return NULL;
5201 if (tqsl_encodeBase64(sig, siglen, reinterpret_cast<char *>(tqsl_static_buf), sizeof tqsl_static_buf))
5202 return NULL;
5203 return reinterpret_cast<char *>(tqsl_static_buf);
5204 }
5205
5206 static bool
5207 safe_strncpy(char *dest, const char *src, int size) {
5208 strncpy(dest, src, size);
5209 dest[size-1] = 0;
5210 return ((static_cast<int>((strlen(src))) < size));
5211 }
5212
5213 static string
5214 tqsl_cert_status_filename(const char *f = "cert_status.xml") {
5215 string s = tQSL_BaseDir;
5216 #ifdef _WIN32
5217 s += "\\";
5218 #else
5219 s += "/";
5220 #endif
5221 s += f;
5222 return s;
5223 }
5224
5225 static int
5226 tqsl_load_cert_status_data(XMLElement &xel) {
5227 int status = xel.parseFile(tqsl_cert_status_filename().c_str());
5228 if (status) {
5229 if (errno == ENOENT) { // No file is OK
5230 tqslTrace("tqsl_load_cert_status_data", "FNF");
5231 return 0;
5232 }
5233 strncpy(tQSL_ErrorFile, tqsl_cert_status_filename().c_str(), sizeof tQSL_ErrorFile);
5234 if (status == XML_PARSE_SYSTEM_ERROR) {
5235 tQSL_Error = TQSL_FILE_SYSTEM_ERROR;
5236 tQSL_Errno = errno;
5237 tqslTrace("tqsl_load_cert_status_data", "open error %s: %s", tqsl_cert_status_filename().c_str(), strerror(tQSL_Errno));
5238 } else {
5239 tqslTrace("tqsl_load_cert_status_data", "syntax error %s", tqsl_cert_status_filename().c_str());
5240 tQSL_Error = TQSL_FILE_SYNTAX_ERROR;
5241 }
5242 return 1;
5243 }
5244 return status;
5245 }
5246
5247 static int
5248 tqsl_dump_cert_status_data(XMLElement &xel) {
5249 ofstream out;
5250 string fn = tqsl_cert_status_filename();
5251
5252 out.exceptions(std::ios::failbit | std::ios::eofbit | std::ios::badbit);
5253 try {
5254 #ifdef _WIN32
5255 wchar_t* wfn = utf8_to_wchar(fn.c_str());
5256 out.open(wfn);
5257 free_wchar(wfn);
5258 #else
5259 out.open(fn.c_str());
5260 #endif
5261 out << xel << endl;
5262 out.close();
5263 }
5264 catch(exception& x) {
5265 tQSL_Error = TQSL_CUSTOM_ERROR;
5266 snprintf(tQSL_CustomError, sizeof tQSL_CustomError,
5267 "Error writing certificate status file (%s): %s/%s",
5268 fn.c_str(), x.what(), strerror(errno));
5269 tqslTrace("tqsl_dump_cert_status_data", "write error %s", tQSL_CustomError);
5270 return 1;
5271 }
5272 return 0;
5273 }
5274
5275 DLLEXPORT int CALLCONVENTION
5276 tqsl_getCertificateStatus(long serial) {
5277 XMLElement top_el;
5278 if (tqsl_load_cert_status_data(top_el))
5279 return TQSL_CERT_STATUS_UNK;
5280 XMLElement sfile;
5281 if (top_el.getFirstElement(sfile)) {
5282 XMLElement cd;
5283 bool ok = sfile.getFirstElement("Cert", cd);
5284 while (ok && cd.getElementName() == "Cert") {
5285 pair<string, bool> s = cd.getAttribute("serial");
5286 if (s.second && strtol(s.first.c_str(), NULL, 10) == serial) {
5287 XMLElement xs;
5288 if (cd.getFirstElement("status", xs)) {
5289 if (!strcasecmp(xs.getText().c_str(), "Bad serial"))
5290 return TQSL_CERT_STATUS_INV;
5291 else if (!strcasecmp(xs.getText().c_str(), "Superceded"))
5292 return TQSL_CERT_STATUS_SUP;
5293 else if (!strcasecmp(xs.getText().c_str(), "Expired"))
5294 return TQSL_CERT_STATUS_EXP;
5295 else if (!strcasecmp(xs.getText().c_str(), "Unrevoked"))
5296 return TQSL_CERT_STATUS_OK;
5297 else
5298 return TQSL_CERT_STATUS_UNK;
5299 }
5300 }
5301 ok = sfile.getNextElement(cd);
5302 }
5303 }
5304 return TQSL_CERT_STATUS_UNK;
5305 }
5306
5307 DLLEXPORT int CALLCONVENTION
5308 tqsl_setCertificateStatus(long serial, const char *status) {
5309 if (status == NULL) {
5310 tqslTrace("tqsl_setCertificateStatus", "status=null");
5311 tQSL_Error = TQSL_ARGUMENT_ERROR;
5312 return 1;
5313 }
5314 char sstr[32];
5315 snprintf(sstr, sizeof sstr, "%ld", serial);
5316
5317 XMLElement top_el;
5318 int stat = tqsl_load_cert_status_data(top_el);
5319 if (stat == TQSL_FILE_SYSTEM_ERROR) {
5320 tqslTrace("tqsl_setCertificateStatus", "error %d", tQSL_Error);
5321 return 1;
5322 }
5323 XMLElement sfile;
5324 if (!top_el.getFirstElement(sfile))
5325 sfile.setElementName("CertStatus");
5326
5327 XMLElementList& ellist = sfile.getElementList();
5328 bool exists = false;
5329 XMLElementList::iterator ep;
5330 for (ep = ellist.find("Cert"); ep != ellist.end(); ep++) {
5331 if (ep->first != "Cert")
5332 break;
5333 pair<string, bool> rval = ep->second->getAttribute("serial");
5334 if (rval.second && strtol(rval.first.c_str(), NULL, 10) == serial) {
5335 exists = true;
5336 break;
5337 }
5338 }
5339
5340 XMLElement *cs = new XMLElement("Cert");
5341 cs->setPretext("\n ");
5342 XMLElement *se = new XMLElement;
5343 se->setPretext(cs->getPretext() + " ");
5344 se->setElementName("status");
5345 se->setText(status);
5346 cs->addElement(se);
5347
5348 cs->setAttribute("serial", sstr);
5349 cs->setText("\n ");
5350
5351 if (exists)
5352 ellist.erase(ep);
5353
5354 sfile.addElement(cs);
5355 sfile.setText("\n");
5356 return tqsl_dump_cert_status_data(sfile);
5357 }
5358
5359 static int
5360 tqsl_clear_deleted(const char *callsign, const char *path, EVP_PKEY *cert_key) {
5361 char newpath[300];
5362 char savepath[300];
5363 #ifdef _WIN32
5364 wchar_t* wnewpath = NULL;
5365 #endif
5366 map<string, string> fields;
5367 vector< map<string, string> > records;
5368 vector< map<string, string> >::iterator it;
5369 EVP_PKEY *new_key = NULL, *key = NULL;
5370 BIO *bio = 0;
5371 FILE *out = 0;
5372 int rval = 1;
5373
5374 if (tqsl_open_key_file(path)) {
5375 if (tQSL_Error != TQSL_SYSTEM_ERROR || tQSL_Errno != ENOENT) {
5376 tqslTrace("tqsl_clear_deleted", "error opening key file %s: %s", path, strerror(tQSL_Errno));
5377 return 1;
5378 }
5379 tQSL_Error = TQSL_NO_ERROR;
5380 }
5381 while (tqsl_read_key(fields) == 0) {
5382 if ((bio = BIO_new_mem_buf(reinterpret_cast<void *>(const_cast<char *>(fields["PUBLIC_KEY"].c_str())),
5383 fields["PUBLIC_KEY"].length())) == NULL) {
5384 tqslTrace("tqsl_clear_deleted", "BIO_new_mem_buf error %s", tqsl_openssl_error());
5385 goto trk_end;
5386 }
5387 if ((key = PEM_read_bio_PUBKEY(bio, NULL, NULL, NULL)) == NULL) {
5388 tqslTrace("tqsl_clear_deleted", "Pem_read_bio_rsa_pubkey error %s", tqsl_openssl_error());
5389 goto trk_end;
5390 }
5391 BIO_free(bio);
5392 bio = NULL;
5393 if (EVP_PKEY_cmp(key, cert_key) == 1) {
5394 fields["DELETED"] = "False";
5395 }
5396 records.push_back(fields);
5397 }
5398 tqsl_close_key_file();
5399 strncpy(newpath, path, sizeof newpath);
5400 strncat(newpath, ".new", sizeof newpath - strlen(newpath)-1);
5401 strncpy(savepath, path, sizeof savepath);
5402 strncat(savepath, ".save", sizeof savepath - strlen(savepath)-1);
5403 #ifdef _WIN32
5404 wnewpath = utf8_to_wchar(newpath);
5405 if ((out = _wfopen(wnewpath, TQSL_OPEN_WRITE)) == NULL) {
5406 free_wchar(wnewpath);
5407 #else
5408 if ((out = fopen(newpath, TQSL_OPEN_WRITE)) == NULL) {
5409 #endif
5410 tQSL_Error = TQSL_SYSTEM_ERROR;
5411 tQSL_Errno = errno;
5412 tqslTrace("tqsl_clear_deleted", "open file %s: %s", newpath, strerror(tQSL_Errno));
5413 goto trk_end;
5414 }
5415 for (it = records.begin(); it != records.end(); it++) {
5416 map<string, string>::iterator mit;
5417 for (mit = it->begin(); mit != it->end(); mit++) {
5418 if (tqsl_write_adif_field(out, mit->first.c_str(), 0, (const unsigned char *)mit->second.c_str(), -1)) {
5419 tqslTrace("tqsl_clear_deleted", "error writing %s", strerror(tQSL_Errno));
5420 #ifdef _WIN32
5421 free_wchar(wnewpath);
5422 #endif
5423 goto trk_end;
5424 }
5425 }
5426 tqsl_write_adif_field(out, "eor", 0, NULL, 0);
5427 }
5428 if (fclose(out) == EOF) {
5429 tQSL_Error = TQSL_SYSTEM_ERROR;
5430 tQSL_Errno = errno;
5431 tqslTrace("tqsl_clear_deleted", "error closing %s", strerror(tQSL_Errno));
5432 #ifdef _WIN32
5433 free_wchar(wnewpath);
5434 #endif
5435 goto trk_end;
5436 }
5437 out = 0;
5438
5439 /* Output file looks okay. Replace the old file with the new one. */
5440 #ifdef _WIN32
5441 wchar_t* wsavepath = utf8_to_wchar(savepath);
5442 if (_wunlink(wsavepath) && errno != ENOENT) {
5443 free_wchar(wsavepath);
5444 free_wchar(wnewpath);
5445 #else
5446 if (unlink(savepath) && errno != ENOENT) {
5447 #endif
5448 tQSL_Error = TQSL_SYSTEM_ERROR;
5449 tQSL_Errno = errno;
5450 tqslTrace("tqsl_clear_deleted", "unlink file %s: %s", savepath, strerror(tQSL_Errno));
5451 goto trk_end;
5452 }
5453 #ifdef _WIN32
5454 wchar_t* wpath = utf8_to_wchar(path);
5455 if (_wrename(wpath, wsavepath) && errno != ENOENT) {
5456 free_wchar(wpath);
5457 free_wchar(wsavepath);
5458 free_wchar(wnewpath);
5459 #else
5460 if (rename(path, savepath) && errno != ENOENT) {
5461 #endif
5462 tQSL_Error = TQSL_SYSTEM_ERROR;
5463 tQSL_Errno = errno;
5464 tqslTrace("tqsl_clear_deleted", "rename file %s->%s: %s", path, savepath, strerror(tQSL_Errno));
5465 goto trk_end;
5466 }
5467 #ifdef _WIN32
5468 if (_wrename(wnewpath, wpath)) {
5469 free_wchar(wnewpath);
5470 free_wchar(wpath);
5471 free_wchar(wsavepath);
5472 #else
5473 if (rename(newpath, path)) {
5474 #endif
5475 tQSL_Error = TQSL_SYSTEM_ERROR;
5476 tQSL_Errno = errno;
5477 tqslTrace("tqsl_clear_deleted", "rename file %s->%s: %s", newpath, path, strerror(tQSL_Errno));
5478 goto trk_end;
5479 }
5480 #ifdef _WIN32
5481 free_wchar(wnewpath);
5482 free_wchar(wpath);
5483 free_wchar(wsavepath);
5484 #endif
5485
5486 rval = 0;
5487 trk_end:
5488 tqsl_close_key_file();
5489 if (out)
5490 fclose(out);
5491 if (new_key)
5492 EVP_PKEY_free(new_key);
5493 if (key)
5494 EVP_PKEY_free(key);
5495 if (bio)
5496 BIO_free(bio);
5497 return rval;
5498 }
5499
5500 static int
5501 tqsl_key_exists(const char *callsign, EVP_PKEY *cert_key) {
5502 map<string, string> fields;
5503 vector< map<string, string> >::iterator it;
5504 EVP_PKEY *key = NULL;
5505 BIO *bio = 0;
5506 int rval = 0;
5507 char path[256];
5508
5509 if (!tqsl_make_key_path(callsign, path, sizeof path)) {
5510 tqslTrace("tqsl_createCertRequest", "make_key_path error %d", errno);
5511 return 0;
5512 }
5513
5514 if (tqsl_open_key_file(path)) {
5515 return 0;
5516 }
5517
5518 while (tqsl_read_key(fields) == 0) {
5519 if ((bio = BIO_new_mem_buf(reinterpret_cast<void *>(const_cast<char *>(fields["PUBLIC_KEY"].c_str())),
5520 fields["PUBLIC_KEY"].length())) == NULL) {
5521 tqslTrace("tqsl_clear_deleted", "BIO_new_mem_buf error %s", tqsl_openssl_error());
5522 goto trk_end;
5523 }
5524 if ((key = PEM_read_bio_PUBKEY(bio, NULL, NULL, NULL)) == NULL) {
5525 tqslTrace("tqsl_clear_deleted", "Pem_read_bio_rsa_pubkey error %s", tqsl_openssl_error());
5526 goto trk_end;
5527 }
5528 BIO_free(bio);
5529 bio = NULL;
5530 if (EVP_PKEY_cmp(key, cert_key) == 1) {
5531 rval = 1;
5532 }
5533 }
5534 trk_end:
5535 tqsl_close_key_file();
5536 if (key)
5537 EVP_PKEY_free(key);
5538 if (bio)
5539 BIO_free(bio);
5540 return rval;
5541 }
5542 /** Save the json results for a given callsign location Detail. */
5543 DLLEXPORT int CALLCONVENTION
5544 tqsl_saveCallsignLocationInfo(const char *callsign, const char *json) {
5545 FILE *out;
5546
5547 if (callsign == NULL || json == NULL) {
5548 tqslTrace("tqsl_saveCallsinLocationInfo", "arg error callsign=0x%lx, json=0x%lx", callsign, json);
5549 tQSL_Error = TQSL_ARGUMENT_ERROR;
5550 return 1;
5551 }
5552 char fixcall[256];
5553 char path[PATH_MAX];
5554 size_t size = sizeof path;
5555
5556 tqsl_clean_call(callsign, fixcall, sizeof fixcall);
5557 strncpy(path, tQSL_BaseDir, size);
5558 #ifdef _WIN32
5559 strncat(path, "\\", size - strlen(path));
5560 #else
5561 strncat(path, "/", size - strlen(path));
5562 #endif
5563 strncat(path, fixcall, size - strlen(path));
5564 strncat(path, ".json", size - strlen(path));
5565 /* Try opening the output stream */
5566
5567 #ifdef _WIN32
5568 wchar_t* wfilename = utf8_to_wchar(path);
5569 if ((out = _wfopen(wfilename, TQSL_OPEN_WRITE)) == NULL) {
5570 free_wchar(wfilename);
5571 #else
5572 if ((out = fopen(path, TQSL_OPEN_WRITE)) == NULL) {
5573 #endif
5574 strncpy(tQSL_ErrorFile, path, sizeof tQSL_ErrorFile);
5575 tqslTrace("tqsl_saveCallsignLocationInfo", "Open file - system error %s", strerror(errno));
5576 tQSL_Error = TQSL_SYSTEM_ERROR;
5577 tQSL_Errno = errno;
5578 return 1;
5579 }
5580 #ifdef _WIN32
5581 free_wchar(wfilename);
5582 #endif
5583 if (fputs(json, out) == EOF) {
5584 strncpy(tQSL_ErrorFile, path, sizeof tQSL_ErrorFile);
5585 tqslTrace("tqsl_createCertRequest", "Write request file - system error %s", strerror(errno));
5586 tQSL_Error = TQSL_SYSTEM_ERROR;
5587 tQSL_Errno = errno;
5588 return 1;
5589 }
5590 if (fclose(out) == EOF) {
5591 strncpy(tQSL_ErrorFile, path, sizeof tQSL_ErrorFile);
5592 tQSL_Error = TQSL_SYSTEM_ERROR;
5593 tQSL_Errno = errno;
5594 tqslTrace("tqsl_saveCallsignLocationInfo", "write error %d", errno);
5595 return 1;
5596 }
5597 return 0;
5598 }
5599
5600 /** Retrieve the json results for a given callsign location Detail. */
5601 DLLEXPORT int CALLCONVENTION
5602 tqsl_getCallsignLocationInfo(const char *callsign, char **buf) {
5603 FILE *in;
5604 static void* mybuf = NULL;
5605 static size_t bufsize = 0;
5606
5607 if (bufsize == 0) {
5608 bufsize = 4096;
5609 mybuf = tqsl_malloc(bufsize);
5610 }
5611 if (callsign == NULL || buf == NULL) {
5612 tqslTrace("tqsl_getCallsinLocationInfo", "arg error callsign=0x%lx, buf=0x%lx", callsign, buf);
5613 tQSL_Error = TQSL_ARGUMENT_ERROR;
5614 return 1;
5615 }
5616 char fixcall[256];
5617 char path[PATH_MAX];
5618 size_t size = sizeof path;
5619
5620 tqsl_clean_call(callsign, fixcall, sizeof fixcall);
5621 strncpy(path, tQSL_BaseDir, size);
5622 #ifdef _WIN32
5623 strncat(path, "\\", size - strlen(path));
5624 #else
5625 strncat(path, "/", size - strlen(path));
5626 #endif
5627 strncat(path, fixcall, size - strlen(path));
5628 strncat(path, ".json", size - strlen(path));
5629
5630 size_t buflen = bufsize;
5631 #ifdef _WIN32
5632 struct _stat32 s;
5633 wchar_t* wfilename = utf8_to_wchar(path);
5634 if (_wstat32(wfilename, &s) == 0) {
5635 buflen = s.st_size + 512;
5636 }
5637 if ((in = _wfopen(wfilename, TQSL_OPEN_READ)) == NULL) {
5638 free_wchar(wfilename);
5639 #else
5640 struct stat s;
5641 if (stat(path, &s) == 0) {
5642 buflen = s.st_size + 512;
5643 }
5644 if ((in = fopen(path, TQSL_OPEN_READ)) == NULL) {
5645 #endif
5646 strncpy(tQSL_ErrorFile, path, sizeof tQSL_ErrorFile);
5647 tqslTrace("tqsl_getCallsignLocationInfo", "Open file - system error %s", strerror(errno));
5648 tQSL_Error = TQSL_SYSTEM_ERROR;
5649 tQSL_Errno = errno;
5650 return 1;
5651 }
5652 #ifdef _WIN32
5653 free_wchar(wfilename);
5654 #endif
5655 if (buflen > bufsize) {
5656 bufsize = buflen + 512;
5657 mybuf = tqsl_realloc(mybuf, bufsize);
5658 }
5659 *buf = reinterpret_cast<char *>(mybuf);
5660 size_t len;
5661 if ((len = fread(mybuf, 1, buflen, in)) == 0) {
5662 strncpy(tQSL_ErrorFile, path, sizeof tQSL_ErrorFile);
5663 tqslTrace("tqsl_getCallsignLocationInformation", "Read file - system error %s", strerror(errno));
5664 tQSL_Error = TQSL_SYSTEM_ERROR;
5665 tQSL_Errno = errno;
5666 return 1;
5667 }
5668 if (fclose(in) == EOF) {
5669 strncpy(tQSL_ErrorFile, path, sizeof tQSL_ErrorFile);
5670 tQSL_Error = TQSL_SYSTEM_ERROR;
5671 tQSL_Errno = errno;
5672 tqslTrace("tqsl_getCallsignLocationInformation", "read error %d", errno);
5673 return 1;
5674 }
5675 if (len < (size_t)buflen) {
5676 char *t = reinterpret_cast<char *>(mybuf);
5677 t[len] = '\0';
5678 }
5679 return 0;
5680 }
5681
5682
5683