/** * gnutls_x509_crl_list_import: * @crls: The structures to store the parsed CRLs. Must not be initialized. * @crl_max: Initially must hold the maximum number of crls. It will be updated with the number of crls available. * @data: The PEM encoded CRLs * @format: One of DER or PEM. * @flags: must be (0) or an OR'd sequence of gnutls_certificate_import_flags. * * This function will convert the given PEM encoded CRL list * to the native gnutls_x509_crl_t format. The output will be stored * in @crls. They will be automatically initialized. * * If the Certificate is PEM encoded it should have a header of "X509 CRL". * * Returns: the number of certificates read or a negative error value. * * Since: 3.0 **/ int gnutls_x509_crl_list_import(gnutls_x509_crl_t * crls, unsigned int *crl_max, const gnutls_datum_t * data, gnutls_x509_crt_fmt_t format, unsigned int flags) { int size; const char *ptr; gnutls_datum_t tmp; int ret, nocopy = 0; unsigned int count = 0, j; if (format == GNUTLS_X509_FMT_DER) { if (*crl_max < 1) { *crl_max = 1; return GNUTLS_E_SHORT_MEMORY_BUFFER; } count = 1; /* import only the first one */ ret = gnutls_x509_crl_init(&crls[0]); if (ret < 0) { gnutls_assert(); goto error; } ret = gnutls_x509_crl_import(crls[0], data, format); if (ret < 0) { gnutls_assert(); goto error; } *crl_max = 1; return 1; } /* move to the certificate */ ptr = memmem(data->data, data->size, PEM_CRL_SEP, sizeof(PEM_CRL_SEP) - 1); if (ptr == NULL) { gnutls_assert(); return GNUTLS_E_BASE64_DECODING_ERROR; } count = 0; do { if (count >= *crl_max) { if (! (flags & GNUTLS_X509_CRT_LIST_IMPORT_FAIL_IF_EXCEED)) break; else nocopy = 1; } if (!nocopy) { ret = gnutls_x509_crl_init(&crls[count]); if (ret < 0) { gnutls_assert(); goto error; } tmp.data = (void *) ptr; tmp.size = data->size - (ptr - (char *) data->data); ret = gnutls_x509_crl_import(crls[count], &tmp, GNUTLS_X509_FMT_PEM); if (ret < 0) { gnutls_assert(); goto error; } } /* now we move ptr after the pem header */ ptr++; /* find the next certificate (if any) */ size = data->size - (ptr - (char *) data->data); if (size > 0) { ptr = memmem(ptr, size, PEM_CRL_SEP, sizeof(PEM_CRL_SEP) - 1); } else ptr = NULL; count++; } while (ptr != NULL); *crl_max = count; if (nocopy == 0) return count; else return GNUTLS_E_SHORT_MEMORY_BUFFER; error: for (j = 0; j < count; j++) gnutls_x509_crl_deinit(crls[j]); return ret; }
/*- * gnutls_x509_verify_certificate: * @cert_list: is the certificate list to be verified * @cert_list_length: holds the number of certificate in cert_list * @CA_list: is the CA list which will be used in verification * @CA_list_length: holds the number of CA certificate in CA_list * @CRL_list: not used * @CRL_list_length: not used * * This function will try to verify the given certificate list and * return its status (TRUSTED, EXPIRED etc.). The return value * (status) should be one or more of the gnutls_certificate_status_t * enumerated elements bitwise or'd. Note that expiration and * activation dates are not checked by this function, you should * check them using the appropriate functions. * * This function understands the basicConstraints (2.5.29.19) PKIX * extension. This means that only a certificate authority can sign * a certificate. * * However you must also check the peer's name in order to check if * the verified certificate belongs to the actual peer. * * The return value (status) should be one or more of the * gnutls_certificate_status_t enumerated elements bitwise or'd. * * GNUTLS_CERT_INVALID: the peer's certificate is not valid. * * GNUTLS_CERT_REVOKED: the certificate has been revoked. * * A negative error code is returned in case of an error. * GNUTLS_E_NO_CERTIFICATE_FOUND is returned to indicate that * no certificate was sent by the peer. -*/ int gnutls_x509_verify_certificate (const gnutls_datum_t * cert_list, int cert_list_length, const gnutls_datum_t * CA_list, int CA_list_length, const gnutls_datum_t * CRL_list, int CRL_list_length) { unsigned int verify; gnutls_x509_crt_t *peer_certificate_list = NULL; gnutls_x509_crt_t *ca_certificate_list = NULL; gnutls_x509_crl_t *crl_list = NULL; int peer_certificate_list_size = 0, i, x, ret; int ca_certificate_list_size = 0, crl_list_size = 0; if (cert_list == NULL || cert_list_length == 0) return GNUTLS_E_NO_CERTIFICATE_FOUND; /* generate a list of gnutls_certs based on the auth info * raw certs. */ peer_certificate_list_size = cert_list_length; peer_certificate_list = gnutls_calloc (peer_certificate_list_size, sizeof (gnutls_x509_crt_t)); if (peer_certificate_list == NULL) { gnutls_assert (); ret = GNUTLS_E_MEMORY_ERROR; goto cleanup; } ca_certificate_list_size = CA_list_length; ca_certificate_list = gnutls_calloc (ca_certificate_list_size, sizeof (gnutls_x509_crt_t)); if (ca_certificate_list == NULL) { gnutls_assert (); ret = GNUTLS_E_MEMORY_ERROR; goto cleanup; } /* allocate memory for CRL */ crl_list_size = CRL_list_length; crl_list = gnutls_calloc (crl_list_size, sizeof (gnutls_x509_crl_t)); if (crl_list == NULL) { gnutls_assert (); ret = GNUTLS_E_MEMORY_ERROR; goto cleanup; } /* convert certA_list to gnutls_cert* list */ for (i = 0; i < peer_certificate_list_size; i++) { ret = gnutls_x509_crt_init (&peer_certificate_list[i]); if (ret < 0) { gnutls_assert (); goto cleanup; } ret = gnutls_x509_crt_import (peer_certificate_list[i], &cert_list[i], GNUTLS_X509_FMT_DER); if (ret < 0) { gnutls_assert (); goto cleanup; } } /* convert CA_list to gnutls_x509_cert* list */ for (i = 0; i < ca_certificate_list_size; i++) { ret = gnutls_x509_crt_init (&ca_certificate_list[i]); if (ret < 0) { gnutls_assert (); goto cleanup; } ret = gnutls_x509_crt_import (ca_certificate_list[i], &CA_list[i], GNUTLS_X509_FMT_DER); if (ret < 0) { gnutls_assert (); goto cleanup; } } #ifdef ENABLE_PKI /* convert CRL_list to gnutls_x509_crl* list */ for (i = 0; i < crl_list_size; i++) { ret = gnutls_x509_crl_init (&crl_list[i]); if (ret < 0) { gnutls_assert (); goto cleanup; } ret = gnutls_x509_crl_import (crl_list[i], &CRL_list[i], GNUTLS_X509_FMT_DER); if (ret < 0) { gnutls_assert (); goto cleanup; } } #endif /* Verify certificate */ ret = gnutls_x509_crt_list_verify (peer_certificate_list, peer_certificate_list_size, ca_certificate_list, ca_certificate_list_size, crl_list, crl_list_size, 0, &verify); if (ret < 0) { gnutls_assert (); goto cleanup; } ret = verify; cleanup: if (peer_certificate_list != NULL) for (x = 0; x < peer_certificate_list_size; x++) { if (peer_certificate_list[x] != NULL) gnutls_x509_crt_deinit (peer_certificate_list[x]); } if (ca_certificate_list != NULL) for (x = 0; x < ca_certificate_list_size; x++) { if (ca_certificate_list[x] != NULL) gnutls_x509_crt_deinit (ca_certificate_list[x]); } #ifdef ENABLE_PKI if (crl_list != NULL) for (x = 0; x < crl_list_size; x++) { if (crl_list[x] != NULL) gnutls_x509_crl_deinit (crl_list[x]); } gnutls_free (crl_list); #endif gnutls_free (ca_certificate_list); gnutls_free (peer_certificate_list); return ret; }
void doit(void) { int exit_val = 0; size_t i; int ret; gnutls_x509_trust_list_t tl; unsigned int verify_status; gnutls_x509_crl_t crl; gnutls_x509_crt_t ca; gnutls_datum_t tmp; /* The overloading of time() seems to work in linux (ELF?) * systems only. Disable it on windows. */ #ifdef _WIN32 exit(77); #endif ret = global_init(); if (ret != 0) { fail("%d: %s\n", ret, gnutls_strerror(ret)); exit(1); } gnutls_global_set_time_function(mytime); gnutls_global_set_log_function(tls_log_func); if (debug) gnutls_global_set_log_level(4711); for (i = 0; crl_list[i].name; i++) { if (debug) printf("Chain '%s' (%d)...\n", crl_list[i].name, (int) i); if (debug > 2) printf("\tAdding CRL..."); ret = gnutls_x509_crl_init(&crl); if (ret < 0) { fprintf(stderr, "gnutls_x509_crl_init[%d]: %s\n", (int) i, gnutls_strerror(ret)); exit(1); } tmp.data = (unsigned char *) *crl_list[i].crl; tmp.size = strlen(*crl_list[i].crl); ret = gnutls_x509_crl_import(crl, &tmp, GNUTLS_X509_FMT_PEM); if (debug > 2) printf("done\n"); if (ret < 0) { fprintf(stderr, "gnutls_x509_crl_import[%s]: %s\n", crl_list[i].name, gnutls_strerror(ret)); exit(1); } gnutls_x509_crl_print(crl, GNUTLS_CRT_PRINT_ONELINE, &tmp); if (debug) printf("\tCRL: %.*s\n", tmp.size, tmp.data); gnutls_free(tmp.data); if (debug > 2) printf("\tAdding CA certificate..."); ret = gnutls_x509_crt_init(&ca); if (ret < 0) { fprintf(stderr, "gnutls_x509_crt_init: %s\n", gnutls_strerror(ret)); exit(1); } tmp.data = (unsigned char *) *crl_list[i].ca; tmp.size = strlen(*crl_list[i].ca); ret = gnutls_x509_crt_import(ca, &tmp, GNUTLS_X509_FMT_PEM); if (ret < 0) { fprintf(stderr, "gnutls_x509_crt_import: %s\n", gnutls_strerror(ret)); exit(1); } if (debug > 2) printf("done\n"); gnutls_x509_crt_print(ca, GNUTLS_CRT_PRINT_ONELINE, &tmp); if (debug) printf("\tCA Certificate: %.*s\n", tmp.size, tmp.data); gnutls_free(tmp.data); if (debug) printf("\tVerifying..."); ret = gnutls_x509_crl_verify(crl, &ca, 1, crl_list[i].verify_flags, &verify_status); if (ret < 0) { fprintf(stderr, "gnutls_x509_crt_list_verify[%d]: %s\n", (int) i, gnutls_strerror(ret)); exit(1); } if (verify_status != crl_list[i].expected_verify_result) { gnutls_datum_t out1, out2; gnutls_certificate_verification_status_print (verify_status, GNUTLS_CRT_X509, &out1, 0); gnutls_certificate_verification_status_print(crl_list [i]. expected_verify_result, GNUTLS_CRT_X509, &out2, 0); fail("chain[%s]:\nverify_status: %d: %s\nexpected: %d: %s\n", crl_list[i].name, verify_status, out1.data, crl_list[i].expected_verify_result, out2.data); gnutls_free(out1.data); gnutls_free(out2.data); if (!debug) exit(1); } else if (debug) printf("done\n"); gnutls_x509_trust_list_init(&tl, 0); ret = gnutls_x509_trust_list_add_cas(tl, &ca, 1, 0); if (ret != 1) { fail("gnutls_x509_trust_list_add_trust_mem\n"); exit(1); } /* make sure that the two functions don't diverge */ ret = gnutls_x509_trust_list_add_crls(tl, &crl, 1, GNUTLS_TL_VERIFY_CRL, crl_list[i].verify_flags); if (crl_list[i].expected_verify_result == 0 && ret < 0) { fprintf(stderr, "gnutls_x509_trust_list_add_crls[%d]: %s\n", (int) i, gnutls_strerror(ret)); exit(1); } if (crl_list[i].expected_verify_result != 0 && ret > 0) { fprintf(stderr, "gnutls_x509_trust_list_add_crls[%d]: succeeded when it shouldn't\n", (int) i); exit(1); } if (debug) printf("\tCleanup..."); gnutls_x509_trust_list_deinit(tl, 0); gnutls_x509_crt_deinit(ca); gnutls_x509_crl_deinit(crl); if (debug) printf("done\n\n\n"); } gnutls_global_deinit(); if (debug) printf("Exit status...%d\n", exit_val); exit(exit_val); }
/** * gnutls_pkcs12_simple_parse: * @p12: the PKCS#12 blob. * @password: optional password used to decrypt PKCS#12 blob, bags and keys. * @key: a structure to store the parsed private key. * @chain: the corresponding to key certificate chain * @chain_len: will be updated with the number of additional * @extra_certs: optional pointer to receive an array of additional * certificates found in the PKCS#12 blob. * @extra_certs_len: will be updated with the number of additional * certs. * @crl: an optional structure to store the parsed CRL. * @flags: should be zero * * This function parses a PKCS#12 blob in @p12blob and extracts the * private key, the corresponding certificate chain, and any additional * certificates and a CRL. * * The @extra_certs_ret and @extra_certs_ret_len parameters are optional * and both may be set to %NULL. If either is non-%NULL, then both must * be. * * MAC:ed PKCS#12 files are supported. Encrypted PKCS#12 bags are * supported. Encrypted PKCS#8 private keys are supported. However, * only password based security, and the same password for all * operations, are supported. * * The private keys may be RSA PKCS#1 or DSA private keys encoded in * the OpenSSL way. * * PKCS#12 file may contain many keys and/or certificates, and there * is no way to identify which key/certificate pair you want. You * should make sure the PKCS#12 file only contain one key/certificate * pair and/or one CRL. * * It is believed that the limitations of this function is acceptable * for most usage, and that any more flexibility would introduce * complexity that would make it harder to use this functionality at * all. * * If the provided structure has encrypted fields but no password * is provided then this function returns %GNUTLS_E_DECRYPTION_FAILED. * * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned, otherwise a * negative error value. * * Since: 3.1 **/ int gnutls_pkcs12_simple_parse (gnutls_pkcs12_t p12, const char *password, gnutls_x509_privkey_t * key, gnutls_x509_crt_t ** chain, unsigned int * chain_len, gnutls_x509_crt_t ** extra_certs, unsigned int * extra_certs_len, gnutls_x509_crl_t * crl, unsigned int flags) { gnutls_pkcs12_bag_t bag = NULL; gnutls_x509_crt_t *_extra_certs = NULL; unsigned int _extra_certs_len = 0; gnutls_x509_crt_t *_chain = NULL; unsigned int _chain_len = 0; int idx = 0; int ret; size_t cert_id_size = 0; size_t key_id_size = 0; opaque cert_id[20]; opaque key_id[20]; int privkey_ok = 0; *key = NULL; if (crl) *crl = NULL; /* find the first private key */ for (;;) { int elements_in_bag; int i; ret = gnutls_pkcs12_bag_init (&bag); if (ret < 0) { bag = NULL; gnutls_assert (); goto done; } ret = gnutls_pkcs12_get_bag (p12, idx, bag); if (ret == GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE) break; if (ret < 0) { gnutls_assert (); goto done; } ret = gnutls_pkcs12_bag_get_type (bag, 0); if (ret < 0) { gnutls_assert (); goto done; } if (ret == GNUTLS_BAG_ENCRYPTED) { if (password == NULL) { ret = gnutls_assert_val(GNUTLS_E_DECRYPTION_FAILED); goto done; } ret = gnutls_pkcs12_bag_decrypt (bag, password); if (ret < 0) { gnutls_assert (); goto done; } } elements_in_bag = gnutls_pkcs12_bag_get_count (bag); if (elements_in_bag < 0) { gnutls_assert (); goto done; } for (i = 0; i < elements_in_bag; i++) { int type; gnutls_datum_t data; type = gnutls_pkcs12_bag_get_type (bag, i); if (type < 0) { gnutls_assert (); goto done; } ret = gnutls_pkcs12_bag_get_data (bag, i, &data); if (ret < 0) { gnutls_assert (); goto done; } switch (type) { case GNUTLS_BAG_PKCS8_ENCRYPTED_KEY: if (password == NULL) { ret = gnutls_assert_val(GNUTLS_E_DECRYPTION_FAILED); goto done; } case GNUTLS_BAG_PKCS8_KEY: if (*key != NULL) /* too simple to continue */ { gnutls_assert (); break; } ret = gnutls_x509_privkey_init (key); if (ret < 0) { gnutls_assert (); goto done; } ret = gnutls_x509_privkey_import_pkcs8 (*key, &data, GNUTLS_X509_FMT_DER, password, type == GNUTLS_BAG_PKCS8_KEY ? GNUTLS_PKCS_PLAIN : 0); if (ret < 0) { gnutls_assert (); gnutls_x509_privkey_deinit (*key); goto done; } key_id_size = sizeof (key_id); ret = gnutls_x509_privkey_get_key_id (*key, 0, key_id, &key_id_size); if (ret < 0) { gnutls_assert (); gnutls_x509_privkey_deinit (*key); goto done; } privkey_ok = 1; /* break */ break; default: break; } } idx++; gnutls_pkcs12_bag_deinit (bag); if (privkey_ok != 0) /* private key was found */ break; } if (privkey_ok == 0) /* no private key */ { gnutls_assert (); return GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE; } /* now find the corresponding certificate */ idx = 0; bag = NULL; for (;;) { int elements_in_bag; int i; ret = gnutls_pkcs12_bag_init (&bag); if (ret < 0) { bag = NULL; gnutls_assert (); goto done; } ret = gnutls_pkcs12_get_bag (p12, idx, bag); if (ret == GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE) break; if (ret < 0) { gnutls_assert (); goto done; } ret = gnutls_pkcs12_bag_get_type (bag, 0); if (ret < 0) { gnutls_assert (); goto done; } if (ret == GNUTLS_BAG_ENCRYPTED) { ret = gnutls_pkcs12_bag_decrypt (bag, password); if (ret < 0) { gnutls_assert (); goto done; } } elements_in_bag = gnutls_pkcs12_bag_get_count (bag); if (elements_in_bag < 0) { gnutls_assert (); goto done; } for (i = 0; i < elements_in_bag; i++) { int type; gnutls_datum_t data; gnutls_x509_crt_t this_cert; type = gnutls_pkcs12_bag_get_type (bag, i); if (type < 0) { gnutls_assert (); goto done; } ret = gnutls_pkcs12_bag_get_data (bag, i, &data); if (ret < 0) { gnutls_assert (); goto done; } switch (type) { case GNUTLS_BAG_CERTIFICATE: ret = gnutls_x509_crt_init (&this_cert); if (ret < 0) { gnutls_assert (); goto done; } ret = gnutls_x509_crt_import (this_cert, &data, GNUTLS_X509_FMT_DER); if (ret < 0) { gnutls_assert (); gnutls_x509_crt_deinit (this_cert); goto done; } /* check if the key id match */ cert_id_size = sizeof (cert_id); ret = gnutls_x509_crt_get_key_id (this_cert, 0, cert_id, &cert_id_size); if (ret < 0) { gnutls_assert (); gnutls_x509_crt_deinit (this_cert); goto done; } if (memcmp (cert_id, key_id, cert_id_size) != 0) { /* they don't match - skip the certificate */ if (extra_certs) { void *tmp = _extra_certs; _extra_certs = gnutls_realloc (_extra_certs, sizeof(_extra_certs[0]) * ++_extra_certs_len); if (!_extra_certs) { gnutls_assert (); gnutls_free(tmp); ret = GNUTLS_E_MEMORY_ERROR; goto done; } _extra_certs[_extra_certs_len - 1] = this_cert; this_cert = NULL; } else { gnutls_x509_crt_deinit (this_cert); } } else { if (_chain_len == 0) { _chain = gnutls_malloc (sizeof(_chain[0]) * (++_chain_len)); if (!_chain) { gnutls_assert (); ret = GNUTLS_E_MEMORY_ERROR; goto done; } _chain[_chain_len - 1] = this_cert; this_cert = NULL; } else { gnutls_x509_crt_deinit (this_cert); } } break; case GNUTLS_BAG_CRL: if (crl == NULL || *crl != NULL) { gnutls_assert (); break; } ret = gnutls_x509_crl_init (crl); if (ret < 0) { gnutls_assert (); goto done; } ret = gnutls_x509_crl_import (*crl, &data, GNUTLS_X509_FMT_DER); if (ret < 0) { gnutls_assert (); gnutls_x509_crl_deinit (*crl); goto done; } break; case GNUTLS_BAG_ENCRYPTED: /* XXX Bother to recurse one level down? Unlikely to use the same password anyway. */ case GNUTLS_BAG_EMPTY: default: break; } } idx++; gnutls_pkcs12_bag_deinit (bag); } if (_chain_len != 1) { ret = GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE; goto done; } ret = make_chain(&_chain, &_chain_len, &_extra_certs, &_extra_certs_len); if (ret < 0) { gnutls_assert(); goto done; } ret = 0; done: if (bag) gnutls_pkcs12_bag_deinit (bag); if (ret < 0) { if (*key) gnutls_x509_privkey_deinit(*key); if (_extra_certs_len && _extra_certs != NULL) { unsigned int i; for (i = 0; i < _extra_certs_len; i++) gnutls_x509_crt_deinit(_extra_certs[i]); gnutls_free(_extra_certs); } if (_chain_len && _chain != NULL) { unsigned int i; for (i = 0; i < _chain_len; i++) gnutls_x509_crt_deinit(_chain[i]); gnutls_free(_chain); } } else { if (extra_certs) { *extra_certs = _extra_certs; *extra_certs_len = _extra_certs_len; } *chain = _chain; *chain_len = _chain_len; } return ret; }
/** Import */ X509CRL(const std::string& crlstr) { int ret = gnutls_x509_crl_import(get(), Datum(crlstr).get(), GNUTLS_X509_FMT_PEM); ThrowOnError(ret, "Unable to load certificate revocation list"); }
int main (void) { int rc; gnutls_certificate_credentials_t crt; gnutls_datum_t crldatum = { crl, strlen (crl) }; gnutls_x509_crl_t crl; rc = gnutls_global_init (); if (rc) { printf ("gnutls_global_init rc %d: %s\n", rc, gnutls_strerror (rc)); return 1; } rc = gnutls_certificate_allocate_credentials (&crt); if (rc) { printf ("gnutls_certificate_allocate_credentials rc %d: %s\n", rc, gnutls_strerror (rc)); return 1; } rc = gnutls_certificate_set_x509_crl_mem (crt, &crldatum, GNUTLS_X509_FMT_PEM); if (rc != 1) { printf ("gnutls_certificate_set_x509_crl_mem num %d\n", rc); return 1; } rc = gnutls_x509_crl_init (&crl); if (rc) { printf ("gnutls_x509_crl_init rc %d: %s\n", rc, gnutls_strerror (rc)); return 1; } rc = gnutls_x509_crl_import (crl, &crldatum, GNUTLS_X509_FMT_PEM); if (rc) { printf ("gnutls_x509_crl_import rc %d: %s\n", rc, gnutls_strerror (rc)); return 1; } rc = gnutls_certificate_set_x509_crl (crt, &crl, 1); if (rc) { printf ("gnutls_certificate_set_x509_crl rc %d: %s\n", rc, gnutls_strerror (rc)); return 1; } gnutls_x509_crl_deinit (crl); gnutls_certificate_free_credentials (crt); gnutls_global_deinit (); return 0; }