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