static bool write_trust_and_rejects (p11_enumerate *ex, node_asn *asn) { p11_array *trusts = NULL; p11_array *rejects = NULL; CK_BBOOL trust; CK_BBOOL distrust; if (!p11_attrs_find_bool (ex->attrs, CKA_TRUSTED, &trust)) trust = CK_FALSE; if (!p11_attrs_find_bool (ex->attrs, CKA_X_DISTRUSTED, &distrust)) distrust = CK_FALSE; if (!load_usage_ext (ex, P11_OID_OPENSSL_REJECT, &rejects)) return_val_if_reached (false); if (distrust) { /* * If this is on the blacklist then, make sure we have * an empty trusts field and add as many things to rejects * as possible. */ trusts = NULL; if (!rejects) rejects = empty_usages (); if (!known_usages (rejects)) return_val_if_reached (false); return_val_if_fail (rejects != NULL, false); } else if (trust) { /* * If this is an anchor, then try and guarantee that there * are some trust anchors. */ if (!load_usage_ext (ex, P11_OID_EXTENDED_KEY_USAGE, &trusts)) return_val_if_reached (false); } else { /* * This is not an anchor, always put an empty trusts * section, with possible rejects, loaded above */ trusts = empty_usages (); } if (!write_usages (asn, "trust", trusts) || !write_usages (asn, "reject", rejects)) return_val_if_reached (false); p11_array_free (trusts); p11_array_free (rejects); return true; }
bool p11_extract_openssl_bundle (p11_enumerate *ex, const char *destination) { p11_save_file *file; p11_buffer output; p11_buffer buf; char *comment; bool ret = true; bool first; CK_RV rv; file = p11_save_open_file (destination, NULL, ex->flags); if (!file) return false; first = true; p11_buffer_init (&output, 0); while ((rv = p11_kit_iter_next (ex->iter)) == CKR_OK) { p11_buffer_init (&buf, 1024); if (!p11_buffer_reset (&output, 2048)) return_val_if_reached (false); if (prepare_pem_contents (ex, &buf)) { if (!p11_pem_write (buf.data, buf.len, "TRUSTED CERTIFICATE", &output)) return_val_if_reached (false); comment = p11_enumerate_comment (ex, first); first = false; ret = p11_save_write (file, comment, -1) && p11_save_write (file, output.data, output.len); free (comment); } p11_buffer_uninit (&buf); if (!ret) break; } p11_buffer_uninit (&output); if (rv != CKR_OK && rv != CKR_CANCEL) { p11_message ("failed to find certificates: %s", p11_kit_strerror (rv)); ret = false; } /* * This will produce an empty file (which is a valid PEM bundle) if no * certificates were found. */ if (!p11_save_finish_file (file, NULL, ret)) ret = false; return ret; }
static bool write_usages (node_asn *asn, const char *field, p11_array *oids) { char *last; int ret; int i; /* * No oids? Then doing this will make the entire optional * field go away */ if (oids == NULL) { ret = asn1_write_value (asn, field, NULL, 0); return_val_if_fail (ret == ASN1_SUCCESS, false); } else { if (asprintf (&last, "%s.?LAST", field) < 0) return_val_if_reached (false); for (i = 0; i < oids->num; i++) { ret = asn1_write_value (asn, field, "NEW", 1); return_val_if_fail (ret == ASN1_SUCCESS, false); ret = asn1_write_value (asn, last, oids->elem[i], -1); return_val_if_fail (ret == ASN1_SUCCESS, false); } free (last); } return true; }
static bool known_usages (p11_array *oids) { char *string; int i; static const char *const strings[] = { P11_OID_SERVER_AUTH_STR, P11_OID_CLIENT_AUTH_STR, P11_OID_CODE_SIGNING_STR, P11_OID_EMAIL_PROTECTION_STR, P11_OID_IPSEC_END_SYSTEM_STR, P11_OID_IPSEC_TUNNEL_STR, P11_OID_IPSEC_USER_STR, P11_OID_TIME_STAMPING_STR, NULL, }; for (i = 0; strings[i] != NULL; i++) { string = strdup (strings[i]); return_val_if_fail (string != NULL, false); if (!p11_array_push (oids, string)) return_val_if_reached (false); } return true; }
static char * symlink_for_subject_hash (p11_enumerate *ex) { unsigned char md[P11_DIGEST_SHA1_LEN]; p11_buffer der; CK_ATTRIBUTE *subject; unsigned long hash; char *linkname = NULL; subject = p11_attrs_find_valid (ex->attrs, CKA_SUBJECT); if (!subject || !subject->pValue || !subject->ulValueLen) return NULL; p11_buffer_init_full (&der, memdup (subject->pValue, subject->ulValueLen), subject->ulValueLen, 0, realloc, free); return_val_if_fail (der.data != NULL, NULL); if (p11_openssl_canon_name_der (ex->asn1_defs, &der)) { p11_digest_sha1 (md, der.data, der.len, NULL); hash = ( ((unsigned long)md[0] ) | ((unsigned long)md[1] << 8L) | ((unsigned long)md[2] << 16L) | ((unsigned long)md[3] << 24L) ) & 0xffffffffL; if (asprintf (&linkname, "%08lx", hash) < 0) return_val_if_reached (NULL); } p11_buffer_uninit (&der); return linkname; }
int p11_tool_getopt (int argc, char *argv[], const struct option *longopts) { p11_buffer buf; int ret; char opt; int i; if (!p11_buffer_init_null (&buf, 64)) return_val_if_reached (-1); for (i = 0; longopts[i].name != NULL; i++) { opt = short_option (longopts[i].val); if (opt != 0) { p11_buffer_add (&buf, &opt, 1); assert (longopts[i].has_arg != optional_argument); if (longopts[i].has_arg == required_argument) p11_buffer_add (&buf, ":", 1); } } ret = getopt_long (argc, argv, buf.data, longopts, NULL); p11_buffer_uninit (&buf); return ret; }
bool p11_array_push (p11_array *array, void *value) { if (!maybe_expand_array (array, array->num + 1)) return_val_if_reached (false); array->elem[array->num] = value; array->num++; return true; }
static p11_array * files_to_attrs (int argc, char *argv[]) { p11_parser *parser; p11_array *parsed; p11_array *array; int ret = P11_PARSE_SUCCESS; int i, j; array = p11_array_new (p11_attrs_free); return_val_if_fail (array != NULL, NULL); parser = create_arg_file_parser (); return_val_if_fail (parser != NULL, NULL); for (i = 0; i < argc; i++) { ret = p11_parse_file (parser, argv[i], NULL, P11_PARSE_FLAG_ANCHOR); switch (ret) { case P11_PARSE_SUCCESS: p11_debug ("parsed file: %s", argv[i]); break; case P11_PARSE_UNRECOGNIZED: p11_message ("unrecognized file format: %s", argv[i]); break; default: p11_message ("failed to parse file: %s", argv[i]); break; } if (ret != P11_PARSE_SUCCESS) break; parsed = p11_parser_parsed (parser); for (j = 0; j < parsed->num; j++) { if (!p11_array_push (array, parsed->elem[j])) return_val_if_reached (NULL); parsed->elem[j] = NULL; } } p11_parser_free (parser); if (ret == P11_PARSE_SUCCESS) return array; p11_array_free (array); return NULL; }
krb5_error_code _adcli_krb5_build_principal (krb5_context k5, const char *user, const char *realm, krb5_principal *principal) { krb5_error_code code; char *name; if (asprintf (&name, "%s@%s", user, realm) < 0) return_val_if_reached (ENOMEM); code = krb5_parse_name (k5, name, principal); return_val_if_fail (code == 0, code); free (name); return 0; }
static bool prepare_pem_contents (p11_enumerate *ex, p11_buffer *buffer) { char message[ASN1_MAX_ERROR_DESCRIPTION_SIZE]; unsigned char *der; node_asn *asn; size_t offset; int ret; int len; p11_buffer_add (buffer, ex->cert_der, ex->cert_len); asn = p11_asn1_create (ex->asn1_defs, "OPENSSL.CertAux"); return_val_if_fail (asn != NULL, false); if (!write_trust_and_rejects (ex, asn) || !write_alias (ex, asn) || !write_keyid (ex, asn) || !write_other (ex, asn)) return_val_if_reached (false); len = 0; offset = buffer->len; ret = asn1_der_coding (asn, "", NULL, &len, message); return_val_if_fail (ret == ASN1_MEM_ERROR, false); der = p11_buffer_append (buffer, len); return_val_if_fail (der != NULL, false); ret = asn1_der_coding (asn, "", der, &len, message); return_val_if_fail (ret == ASN1_SUCCESS, false); buffer->len = offset + len; asn1_delete_structure (&asn); return true; }
static bool load_attached_extension (p11_dict *attached, p11_dict *asn1_defs, const unsigned char *der, size_t len) { char message[ASN1_MAX_ERROR_DESCRIPTION_SIZE]; node_asn *ext; char *oid; int length; int start; int end; int ret; ext = p11_asn1_decode (asn1_defs, "PKIX1.Extension", der, len, message); if (ext == NULL) { p11_message ("couldn't parse attached certificate extension: %s", message); return false; } ret = asn1_der_decoding_startEnd (ext, der, len, "extnID", &start, &end); return_val_if_fail (ret == ASN1_SUCCESS, false); /* Make sure it's a straightforward oid with certain assumptions */ length = (end - start) + 1; if (!p11_oid_simple (der + start, length)) { p11_debug ("strange complex certificate extension object id"); return false; } oid = memdup (der + start, length); return_val_if_fail (oid != NULL, false); if (!p11_dict_set (attached, oid, ext)) return_val_if_reached (false); return true; }
char * _adcli_krb5_format_enctypes (krb5_enctype *enctypes) { char *value; int types; int i; types = 0; for (i = 0; enctypes[i] != 0; i++) { switch (enctypes[i]) { case ENCTYPE_DES_CBC_CRC: types |= MS_KERB_ENCTYPE_DES_CBC_CRC; break; case ENCTYPE_DES_CBC_MD5: types |= MS_KERB_ENCTYPE_DES_CBC_MD5; break; case ENCTYPE_ARCFOUR_HMAC: types |= MS_KERB_ENCTYPE_RC4_HMAC_MD5; break; case ENCTYPE_AES128_CTS_HMAC_SHA1_96: types |= MS_KERB_ENCTYPE_AES128_CTC_HMAC_SHA1_96; break; case ENCTYPE_AES256_CTS_HMAC_SHA1_96: types |= MS_KERB_ENCTYPE_AES256_CTS_HMAC_SHA1_96; break; default: break; } } if (types == 0) return NULL; if (asprintf (&value, "%d", types) < 0) return_val_if_reached (NULL); return value; }
static char * symlink_for_subject_old_hash (p11_enumerate *ex) { unsigned char md[P11_DIGEST_MD5_LEN]; CK_ATTRIBUTE *subject; unsigned long hash; char *linkname; subject = p11_attrs_find_valid (ex->attrs, CKA_SUBJECT); if (!subject) return NULL; p11_digest_md5 (md, subject->pValue, (size_t)subject->ulValueLen, NULL); hash = ( ((unsigned long)md[0] ) | ((unsigned long)md[1] << 8L) | ((unsigned long)md[2] << 16L) | ((unsigned long)md[3] << 24L) ) & 0xffffffffL; if (asprintf (&linkname, "%08lx", hash) < 0) return_val_if_reached (NULL); return linkname; }
bool p11_openssl_canon_string_der (p11_buffer *der) { char *string; size_t length; int output_len; int len_len; bool unknown_string; unsigned char *output; int len; string = p11_x509_parse_directory_string (der->data, der->len, &unknown_string, &length); /* Just pass through all the non-string types */ if (string == NULL) return unknown_string; p11_openssl_canon_string (string, &length); asn1_length_der (length, NULL, &len_len); output_len = 1 + len_len + length; if (!p11_buffer_reset (der, output_len)) return_val_if_reached (false); output = der->data; der->len = output_len; output[0] = 12; /* UTF8String */ len = output_len - 1; asn1_octet_der ((unsigned char *)string, length, output + 1, &len); assert (len == output_len - 1); free (string); return true; }
p11_save_file * p11_save_open_file (const char *path, const char *extension, int flags) { p11_save_file *file; char *temp; int fd; return_val_if_fail (path != NULL, NULL); if (extension == NULL) extension = ""; if (asprintf (&temp, "%s%s.XXXXXX", path, extension) < 0) return_val_if_reached (NULL); fd = mkstemp (temp); if (fd < 0) { p11_message_err (errno, "couldn't create file: %s%s", path, extension); free (temp); return NULL; } file = calloc (1, sizeof (p11_save_file)); return_val_if_fail (file != NULL, NULL); file->temp = temp; file->bare = strdup (path); return_val_if_fail (file->bare != NULL, NULL); file->extension = strdup (extension); return_val_if_fail (file->extension != NULL, NULL); file->flags = flags; file->fd = fd; return file; }
bool p11_extract_openssl_directory (p11_enumerate *ex, const char *destination) { char *filename; p11_save_file *file; p11_save_dir *dir; p11_buffer output; p11_buffer buf; bool ret = true; char *path; char *name; CK_RV rv; dir = p11_save_open_directory (destination, ex->flags); if (dir == NULL) return false; p11_buffer_init (&buf, 0); p11_buffer_init (&output, 0); while ((rv = p11_kit_iter_next (ex->iter)) == CKR_OK) { if (!p11_buffer_reset (&buf, 1024)) return_val_if_reached (false); if (!p11_buffer_reset (&output, 2048)) return_val_if_reached (false); if (prepare_pem_contents (ex, &buf)) { if (!p11_pem_write (buf.data, buf.len, "TRUSTED CERTIFICATE", &output)) return_val_if_reached (false); name = p11_enumerate_filename (ex); return_val_if_fail (name != NULL, false); filename = NULL; path = NULL; ret = false; file = p11_save_open_file_in (dir, name, ".pem"); if (file != NULL) { ret = p11_save_write (file, output.data, output.len); if (!p11_save_finish_file (file, &path, ret)) ret = false; if (ret) filename = p11_path_base (path); } ret = p11_openssl_symlink(ex, dir, filename); free (filename); free (path); free (name); } if (!ret) break; } p11_buffer_uninit (&buf); p11_buffer_uninit (&output); if (rv != CKR_OK && rv != CKR_CANCEL) { p11_message ("failed to find certificates: %s", p11_kit_strerror (rv)); ret = false; } p11_save_finish_directory (dir, ret); return ret; }
bool p11_openssl_canon_name_der (p11_dict *asn1_defs, p11_buffer *der) { p11_buffer value; char outer[64]; char field[64]; node_asn *name; void *at; int value_len; bool failed; size_t offset; int ret; int num; int len; int i, j; name = p11_asn1_decode (asn1_defs, "PKIX1.Name", der->data, der->len, NULL); return_val_if_fail (name != NULL, false); ret = asn1_number_of_elements (name, "rdnSequence", &num); return_val_if_fail (ret == ASN1_SUCCESS, false); p11_buffer_init (&value, 0); p11_buffer_reset (der, 0); for (i = 1, failed = false; !failed && i < num + 1; i++) { snprintf (outer, sizeof (outer), "rdnSequence.?%d", i); for (j = 1; !failed; j++) { snprintf (field, sizeof (field), "%s.?%d.value", outer, j); value_len = 0; ret = asn1_read_value (name, field, NULL, &value_len); if (ret == ASN1_ELEMENT_NOT_FOUND) break; return_val_if_fail (ret == ASN1_MEM_ERROR, false); if (!p11_buffer_reset (&value, value_len)) return_val_if_reached (false); ret = asn1_read_value (name, field, value.data, &value_len); return_val_if_fail (ret == ASN1_SUCCESS, false); value.len = value_len; if (p11_openssl_canon_string_der (&value)) { ret = asn1_write_value (name, field, value.data, value.len); return_val_if_fail (ret == ASN1_SUCCESS, false); } else { failed = true; } } /* * Yes the OpenSSL canon strangeness, is a concatenation * of all the RelativeDistinguishedName DER encodings, without * an outside wrapper. */ if (!failed) { len = -1; ret = asn1_der_coding (name, outer, NULL, &len, NULL); return_val_if_fail (ret == ASN1_MEM_ERROR, false); offset = der->len; at = p11_buffer_append (der, len); return_val_if_fail (at != NULL, false); ret = asn1_der_coding (name, outer, at, &len, NULL); return_val_if_fail (ret == ASN1_SUCCESS, false); der->len = offset + len; } } asn1_delete_structure (&name); p11_buffer_uninit (&value); return !failed; }
bool p11_save_finish_file (p11_save_file *file, char **path_out, bool commit) { bool ret = true; char *path; if (!file) return false; if (!commit) { close (file->fd); unlink (file->temp); filo_free (file); return true; } if (asprintf (&path, "%s%s", file->bare, file->extension) < 0) return_val_if_reached (false); if (close (file->fd) < 0) { p11_message_err (errno, "couldn't write file: %s", file->temp); ret = false; #ifdef OS_UNIX /* Set the mode of the file, readable by everyone, but not writable */ } else if (chmod (file->temp, S_IRUSR | S_IRGRP | S_IROTH) < 0) { p11_message_err (errno, "couldn't set file permissions: %s", file->temp); ret = false; /* Atomically rename the tempfile over the filename */ } else if (file->flags & P11_SAVE_OVERWRITE) { if (rename (file->temp, path) < 0) { p11_message_err (errno, "couldn't complete writing file: %s", path); ret = false; } else { unlink (file->temp); } /* Create a unique name if requested unique file name */ } else if (file->flags & P11_SAVE_UNIQUE) { free (path); path = make_unique_name (file->bare, file->extension, on_unique_try_link, file); if (!path) ret = false; unlink (file->temp); /* When not overwriting, link will fail if filename exists. */ } else { if (link (file->temp, path) < 0) { p11_message_err (errno, "couldn't complete writing of file: %s", path); ret = false; } unlink (file->temp); #else /* OS_WIN32 */ /* Windows does not do atomic renames, so delete original file first */ } else { /* Create a unique name if requested unique file name */ if (file->flags & P11_SAVE_UNIQUE) {
static p11_array * uris_or_files_to_iters (int argc, char *argv[], int behavior) { int flags = P11_KIT_URI_FOR_OBJECT_ON_TOKEN_AND_MODULE; p11_parser *parser = NULL; p11_array *iters; p11_array *parsed; p11_kit_uri *uri; p11_kit_iter *iter; int ret; int i, j; iters = p11_array_new ((p11_destroyer)p11_kit_iter_free); return_val_if_fail (iters != NULL, NULL); for (i = 0; i < argc; i++) { /* A PKCS#11 URI */ if (strncmp (argv[i], "pkcs11:", 7) == 0) { uri = p11_kit_uri_new (); if (p11_kit_uri_parse (argv[i], flags, uri) != P11_KIT_URI_OK) { p11_message ("invalid PKCS#11 uri: %s", argv[i]); p11_kit_uri_free (uri); break; } iter = p11_kit_iter_new (uri, behavior); return_val_if_fail (iter != NULL, NULL); p11_kit_uri_free (uri); if (!p11_array_push (iters, iter)) return_val_if_reached (NULL); } else { if (parser == NULL) parser = create_arg_file_parser (); ret = p11_parse_file (parser, argv[i], NULL, P11_PARSE_FLAG_ANCHOR); switch (ret) { case P11_PARSE_SUCCESS: p11_debug ("parsed file: %s", argv[i]); break; case P11_PARSE_UNRECOGNIZED: p11_message ("unrecognized file format: %s", argv[i]); break; default: p11_message ("failed to parse file: %s", argv[i]); break; } if (ret != P11_PARSE_SUCCESS) break; parsed = p11_parser_parsed (parser); for (j = 0; j < parsed->num; j++) { iter = p11_kit_iter_new (NULL, behavior); return_val_if_fail (iter != NULL, NULL); iter_match_anchor (iter, parsed->elem[j]); if (!p11_array_push (iters, iter)) return_val_if_reached (NULL); } } } if (parser) p11_parser_free (parser); if (argc != i) { p11_array_free (iters); return NULL; } return iters; }