2 * Copyright (C) 2012 Free Software Foundation, Inc.
4 * Author: Nikos Mavrogiannopoulos
6 * This file is part of GnuTLS.
8 * The GnuTLS is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public License
10 * as published by the Free Software Foundation; either version 3 of
11 * the License, or (at your option) any later version.
13 * This library is distributed in the hope that it will be useful, but
14 * WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Lesser General Public License for more details.
18 * You should have received a copy of the GNU Lesser General Public License
19 * along with this program. If not, see <http://www.gnu.org/licenses/>
23 #include <gnutls_int.h>
24 #include <gnutls_errors.h>
26 #include <gnutls_global.h>
27 #include <gnutls_num.h> /* MAX */
28 #include <gnutls_sig.h>
29 #include <gnutls_str.h>
30 #include <gnutls_datum.h>
35 #include <gnutls/abstract.h>
38 static int raw_pubkey_to_base64(gnutls_datum_t
* pubkey
);
39 static int x509_crt_to_raw_pubkey(const gnutls_datum_t
* cert
, gnutls_datum_t
*rpubkey
);
40 static int pgp_crt_to_raw_pubkey(const gnutls_datum_t
* cert
, gnutls_datum_t
*rpubkey
);
41 static int find_stored_pubkey(const char* file
, const char* application
,
42 const char* host
, const char* service
,
43 const gnutls_datum_t
* skey
);
44 static int find_config_file(char* file
, size_t max_size
);
45 #define MAX_FILENAME 512
48 * gnutls_verify_stored_pubkey:
49 * @file: A file specifying the stored keys (use NULL for the default)
50 * @application: non-NULL with an application name if this key is application-specific
51 * @host: The peer's name
52 * @service: non-NULL if this key is specific to a service (e.g. http)
53 * @cert_type: The type of the certificate
54 * @cert: The raw (der) data of the certificate
55 * @flags: should be 0.
57 * This function will try to verify the provided certificate using
58 * a list of stored public keys. The @service field if non-NULL should
61 * Returns: If no associated public key is found
62 * then %GNUTLS_E_NO_CERTIFICATE_FOUND will be returned. If a key
63 * is found but does not match %GNUTLS_E_CERTIFICATE_KEY_MISMATCH
64 * is returned. On success, %GNUTLS_E_SUCCESS (0) is returned,
65 * or a negative error value on other errors.
70 gnutls_verify_stored_pubkey(const char* file
,
71 const char* application
,
74 gnutls_certificate_type_t cert_type
,
75 const gnutls_datum_t
* cert
, unsigned int flags
)
77 gnutls_datum_t pubkey
= { NULL
, 0 };
79 char local_file
[MAX_FILENAME
];
81 if (cert_type
!= GNUTLS_CRT_X509
&& cert_type
!= GNUTLS_CRT_OPENPGP
)
82 return gnutls_assert_val(GNUTLS_E_UNSUPPORTED_CERTIFICATE_TYPE
);
86 ret
= find_config_file(local_file
, sizeof(local_file
));
88 return gnutls_assert_val(ret
);
92 if (cert_type
== GNUTLS_CRT_X509
)
93 ret
= x509_crt_to_raw_pubkey(cert
, &pubkey
);
95 ret
= pgp_crt_to_raw_pubkey(cert
, &pubkey
);
103 ret
= raw_pubkey_to_base64(&pubkey
);
110 ret
= find_stored_pubkey(file
, application
, host
, service
, &pubkey
);
112 return gnutls_assert_val(GNUTLS_E_NO_CERTIFICATE_FOUND
);
116 gnutls_free(pubkey
.data
);
120 static int parse_line(char* line
, const char* application
,
121 size_t application_len
,
122 const char* host
, size_t host_len
,
123 const char* service
, size_t service_len
,
124 const gnutls_datum_t
*skey
)
131 p
= strtok_r(line
, "|", &savep
);
133 return gnutls_assert_val(GNUTLS_E_PARSING_ERROR
);
135 if (strncmp(p
, "g0", 2) != 0)
136 return gnutls_assert_val(GNUTLS_E_PARSING_ERROR
);
138 /* read application */
139 p
= strtok_r(NULL
, "|", &savep
);
141 return gnutls_assert_val(GNUTLS_E_PARSING_ERROR
);
143 if (p
[0] != '*' && strcmp(p
, application
)!=0)
144 return gnutls_assert_val(GNUTLS_E_PARSING_ERROR
);
147 p
= strtok_r(NULL
, "|", &savep
);
149 return gnutls_assert_val(GNUTLS_E_PARSING_ERROR
);
151 if (p
[0] != '*' && strcmp(p
, host
) != 0)
152 return gnutls_assert_val(GNUTLS_E_PARSING_ERROR
);
155 p
= strtok_r(NULL
, "|", &savep
);
157 return gnutls_assert_val(GNUTLS_E_PARSING_ERROR
);
159 if (p
[0] != '*' && strcmp(p
, service
) != 0)
160 return gnutls_assert_val(GNUTLS_E_PARSING_ERROR
);
163 kp
= strtok_r(NULL
, "|", &savep
);
165 return gnutls_assert_val(GNUTLS_E_PARSING_ERROR
);
167 p
= strpbrk(kp
, "\n \r\t|");
168 if (p
!= NULL
) *p
= 0;
171 if (kp_len
!= skey
->size
)
172 return gnutls_assert_val(GNUTLS_E_CERTIFICATE_KEY_MISMATCH
);
174 if (memcmp(kp
, skey
->data
, skey
->size
) != 0)
175 return gnutls_assert_val(GNUTLS_E_CERTIFICATE_KEY_MISMATCH
);
177 /* key found and matches */
181 /* Returns the base64 key if found
183 static int find_stored_pubkey(const char* file
, const char* application
,
184 const char* host
, const char* service
,
185 const gnutls_datum_t
* skey
)
189 size_t line_size
= 0;
190 int ret
, l2
, mismatch
= 0;
191 size_t application_len
= 0, host_len
= 0, service_len
= 0;
193 if (host
!= NULL
) host_len
= strlen(host
);
194 if (service
!= NULL
) service_len
= strlen(service
);
195 if (application
!= NULL
) application_len
= strlen(application
);
197 fd
= fopen(file
, "rb");
199 return gnutls_assert_val(GNUTLS_E_FILE_ERROR
);
203 l2
= getline(&line
, &line_size
, fd
);
206 ret
= parse_line(line
, application
, application_len
,
207 host
, host_len
, service
, service_len
, skey
);
208 if (ret
== 0) /* found */
212 else if (ret
== GNUTLS_E_CERTIFICATE_KEY_MISMATCH
)
219 ret
= GNUTLS_E_CERTIFICATE_KEY_MISMATCH
;
221 ret
= GNUTLS_E_NO_CERTIFICATE_FOUND
;
230 static int raw_pubkey_to_base64(gnutls_datum_t
* pubkey
)
235 ret
= base64_encode_alloc((void*)pubkey
->data
, pubkey
->size
, &out
);
237 return gnutls_assert_val(GNUTLS_E_MEMORY_ERROR
);
239 gnutls_free(pubkey
->data
);
240 pubkey
->data
= (void*)out
;
246 static int x509_crt_to_raw_pubkey(const gnutls_datum_t
* cert
, gnutls_datum_t
*rpubkey
)
248 gnutls_x509_crt_t crt
= NULL
;
249 gnutls_pubkey_t pubkey
= NULL
;
253 ret
= gnutls_x509_crt_init(&crt
);
255 return gnutls_assert_val(ret
);
257 ret
= gnutls_pubkey_init(&pubkey
);
264 ret
= gnutls_x509_crt_import(crt
, cert
, GNUTLS_X509_FMT_DER
);
271 ret
= gnutls_pubkey_import_x509 (pubkey
, crt
, 0);
279 ret
= gnutls_pubkey_export(pubkey
, GNUTLS_X509_FMT_DER
, NULL
, &size
);
280 if (ret
< 0 && ret
!= GNUTLS_E_SHORT_MEMORY_BUFFER
)
286 rpubkey
->data
= gnutls_malloc(size
);
287 if (rpubkey
->data
== NULL
)
288 if (ret
< 0 && ret
!= GNUTLS_E_SHORT_MEMORY_BUFFER
)
290 ret
= GNUTLS_E_MEMORY_ERROR
;
295 ret
= gnutls_pubkey_export(pubkey
, GNUTLS_X509_FMT_DER
, rpubkey
->data
, &size
);
298 gnutls_free(rpubkey
->data
);
303 rpubkey
->size
= size
;
307 gnutls_x509_crt_deinit(crt
);
308 gnutls_pubkey_deinit(pubkey
);
313 static int pgp_crt_to_raw_pubkey(const gnutls_datum_t
* cert
, gnutls_datum_t
*rpubkey
)
315 gnutls_openpgp_crt_t crt
= NULL
;
316 gnutls_pubkey_t pubkey
= NULL
;
320 ret
= gnutls_openpgp_crt_init(&crt
);
322 return gnutls_assert_val(ret
);
324 ret
= gnutls_pubkey_init(&pubkey
);
331 ret
= gnutls_openpgp_crt_import(crt
, cert
, GNUTLS_OPENPGP_FMT_RAW
);
338 ret
= gnutls_pubkey_import_openpgp (pubkey
, crt
, 0);
346 ret
= gnutls_pubkey_export(pubkey
, GNUTLS_X509_FMT_DER
, NULL
, &size
);
347 if (ret
< 0 && ret
!= GNUTLS_E_SHORT_MEMORY_BUFFER
)
353 rpubkey
->data
= gnutls_malloc(size
);
354 if (rpubkey
->data
== NULL
)
355 if (ret
< 0 && ret
!= GNUTLS_E_SHORT_MEMORY_BUFFER
)
357 ret
= GNUTLS_E_MEMORY_ERROR
;
362 ret
= gnutls_pubkey_export(pubkey
, GNUTLS_X509_FMT_DER
, rpubkey
->data
, &size
);
365 gnutls_free(rpubkey
->data
);
370 rpubkey
->size
= size
;
374 gnutls_openpgp_crt_deinit(crt
);
375 gnutls_pubkey_deinit(pubkey
);
381 * gnutls_store_pubkey:
382 * @file: A file specifying the stored keys (use NULL for the default)
383 * @application: non-NULL with an application name if this key is application-specific
384 * @host: The peer's name
385 * @service: non-NULL if this key is specific to a service (e.g. http)
386 * @cert_type: The type of the certificate
387 * @cert: The data of the certificate
388 * @flags: should be 0.
390 * This function will store to verify the provided certificate to
391 * the list of stored public keys.
393 * Note that this function is not thread safe.
395 * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned, otherwise a
396 * negative error value.
401 gnutls_store_pubkey(const char* file
,
402 const char* application
,
405 gnutls_certificate_type_t cert_type
,
406 const gnutls_datum_t
* cert
, unsigned int flags
)
409 gnutls_datum_t pubkey
= { NULL
, 0 };
411 char local_file
[MAX_FILENAME
];
413 if (cert_type
!= GNUTLS_CRT_X509
&& cert_type
!= GNUTLS_CRT_OPENPGP
)
414 return gnutls_assert_val(GNUTLS_E_UNSUPPORTED_CERTIFICATE_TYPE
);
418 ret
= _gnutls_find_config_path(local_file
, sizeof(local_file
));
420 return gnutls_assert_val(ret
);
422 _gnutls_debug_log("Configuration path: %s\n", local_file
);
423 mkdir(local_file
, 0700);
425 ret
= find_config_file(local_file
, sizeof(local_file
));
427 return gnutls_assert_val(ret
);
431 if (cert_type
== GNUTLS_CRT_X509
)
432 ret
= x509_crt_to_raw_pubkey(cert
, &pubkey
);
434 ret
= pgp_crt_to_raw_pubkey(cert
, &pubkey
);
441 ret
= raw_pubkey_to_base64(&pubkey
);
448 _gnutls_debug_log("Configuration file: %s\n", file
);
450 fd
= fopen(file
, "ab+");
453 ret
= gnutls_assert_val(GNUTLS_E_FILE_ERROR
);
457 if (application
== NULL
) application
= "*";
458 if (service
== NULL
) service
= "*";
459 if (host
== NULL
) host
= "*";
461 fprintf(fd
, "|g0|%s|%s|%s|%.*s\n", application
, host
, service
, pubkey
.size
, pubkey
.data
);
466 gnutls_free(pubkey
.data
);
467 if (fd
!= NULL
) fclose(fd
);
472 #define CONFIG_FILE "known_hosts"
474 static int find_config_file(char* file
, size_t max_size
)
476 char path
[MAX_FILENAME
];
479 ret
= _gnutls_find_config_path(path
, sizeof(path
));
481 return gnutls_assert_val(ret
);
484 snprintf(file
, max_size
, "%s", CONFIG_FILE
);
486 snprintf(file
, max_size
, "%s/%s", path
, CONFIG_FILE
);