static EVP_PKEY *pkcs11_load_key(ENGINE_CTX *ctx, const char *s_slot_key_id, UI_METHOD * ui_method, void *callback_data, int isPrivate) { PKCS11_SLOT *slot; PKCS11_SLOT *found_slot = NULL; PKCS11_TOKEN *tok, *match_tok = NULL; PKCS11_KEY *keys, *selected_key = NULL; PKCS11_CERT *certs; EVP_PKEY *pk; unsigned int cert_count, key_count, n, m; unsigned char key_id[MAX_VALUE_LEN / 2]; size_t key_id_len = sizeof(key_id); char *key_label = NULL; int slot_nr = -1; char tmp_pin[MAX_PIN_LENGTH]; size_t tmp_pin_len = sizeof(tmp_pin); char flags[64]; if (pkcs11_init_libp11(ctx)) /* Delayed libp11 initialization */ return NULL; if (ctx->verbose) fprintf(stderr, "Loading %s key \"%s\"\n", (char *)(isPrivate ? "private" : "public"), s_slot_key_id); if (s_slot_key_id && *s_slot_key_id) { if (!strncmp(s_slot_key_id, "pkcs11:", 7)) { n = parse_pkcs11_uri(s_slot_key_id, &match_tok, key_id, &key_id_len, tmp_pin, &tmp_pin_len, &key_label); if (n && tmp_pin_len > 0 && tmp_pin[0] != 0) { destroy_pin(ctx); ctx->pin = OPENSSL_malloc(MAX_PIN_LENGTH * sizeof(char)); if (ctx->pin != NULL) { memset(ctx->pin, 0, MAX_PIN_LENGTH * sizeof(char)); memcpy(ctx->pin, tmp_pin, tmp_pin_len); ctx->pin_length = tmp_pin_len; } } if (!n) { fprintf(stderr, "The certificate ID is not a valid PKCS#11 URI\n" "The PKCS#11 URI format is defined by RFC7512\n"); return NULL; } } else { n = parse_slot_id_string(s_slot_key_id, &slot_nr, key_id, &key_id_len, &key_label); if (!n) { fprintf(stderr, "The certificate ID is not a valid PKCS#11 URI\n" "The PKCS#11 URI format is defined by RFC7512\n" "The legacy ENGINE_pkcs11 ID format is also " "still accepted for now\n"); return NULL; } } if (ctx->verbose) { fprintf(stderr, "Looking in slot %d for key: ", slot_nr); if (key_label == NULL) { for (n = 0; n < key_id_len; n++) fprintf(stderr, "%02x", key_id[n]); fprintf(stderr, "\n"); } else fprintf(stderr, "label: %s\n", key_label); } } for (n = 0; n < ctx->slot_count; n++) { slot = ctx->slot_list + n; flags[0] = '\0'; if (slot->token) { if (!slot->token->initialized) strcat(flags, "uninitialized, "); else if (!slot->token->userPinSet) strcat(flags, "no pin, "); if (slot->token->loginRequired) strcat(flags, "login, "); if (slot->token->readOnly) strcat(flags, "ro, "); } else { strcpy(flags, "no token"); } if ((m = strlen(flags)) != 0) { flags[m - 2] = '\0'; } if (slot_nr != -1 && slot_nr == (int)PKCS11_get_slotid_from_slot(slot)) { found_slot = slot; } if (match_tok && slot->token && (match_tok->label == NULL || !strcmp(match_tok->label, slot->token->label)) && (match_tok->manufacturer == NULL || !strcmp(match_tok->manufacturer, slot->token->manufacturer)) && (match_tok->serialnr == NULL || !strcmp(match_tok->serialnr, slot->token->serialnr)) && (match_tok->model == NULL || !strcmp(match_tok->model, slot->token->model))) { found_slot = slot; } if (ctx->verbose) { fprintf(stderr, "[%lu] %-25.25s %-16s", PKCS11_get_slotid_from_slot(slot), slot->description, flags); if (slot->token) { fprintf(stderr, " (%s)", slot->token->label[0] ? slot->token->label : "no label"); } fprintf(stderr, "\n"); } } if (match_tok) { OPENSSL_free(match_tok->model); OPENSSL_free(match_tok->manufacturer); OPENSSL_free(match_tok->serialnr); OPENSSL_free(match_tok->label); OPENSSL_free(match_tok); } if (found_slot) { slot = found_slot; } else if (match_tok) { fprintf(stderr, "Specified object not found\n"); return NULL; } else if (slot_nr == -1) { if (!(slot = PKCS11_find_token(ctx->pkcs11_ctx, ctx->slot_list, ctx->slot_count))) { fprintf(stderr, "No tokens found\n"); return NULL; } } else { fprintf(stderr, "Invalid slot number: %d\n", slot_nr); return NULL; } tok = slot->token; if (tok == NULL) { fprintf(stderr, "Found empty token\n"); return NULL; } /* The following check is non-critical to ensure interoperability * with some other (which ones?) PKCS#11 libraries */ if (!tok->initialized) fprintf(stderr, "Found uninitialized token\n"); if (isPrivate && !tok->userPinSet && !tok->readOnly) { fprintf(stderr, "Found slot without user PIN\n"); return NULL; } if (ctx->verbose) { fprintf(stderr, "Found slot: %s\n", slot->description); fprintf(stderr, "Found token: %s\n", slot->token->label); } if (PKCS11_enumerate_certs(tok, &certs, &cert_count)) { fprintf(stderr, "Unable to enumerate certificates\n"); return NULL; } if (ctx->verbose) { fprintf(stderr, "Found %u certificate%s:\n", cert_count, (cert_count <= 1) ? "" : "s"); for (n = 0; n < cert_count; n++) { PKCS11_CERT *c = certs + n; char *dn = NULL; fprintf(stderr, " %2u %s", n + 1, c->label); if (c->x509) dn = X509_NAME_oneline(X509_get_subject_name(c->x509), NULL, 0); if (dn) { fprintf(stderr, " (%s)", dn); OPENSSL_free(dn); } fprintf(stderr, "\n"); } } if (isPrivate) { /* Perform login to the token if required */ if (!pkcs11_login(ctx, slot, tok, ui_method, callback_data)) { fprintf(stderr, "login to token failed, returning NULL...\n"); return NULL; } /* Make sure there is at least one private key on the token */ if (PKCS11_enumerate_keys(tok, &keys, &key_count)) { fprintf(stderr, "Unable to enumerate private keys\n"); return NULL; } } else { /* Make sure there is at least one public key on the token */ if (PKCS11_enumerate_public_keys(tok, &keys, &key_count)) { fprintf(stderr, "Unable to enumerate public keys\n"); return NULL; } } if (key_count == 0) { fprintf(stderr, "No %s keys found.\n", (char *)(isPrivate ? "private" : "public")); return NULL; } if (ctx->verbose) fprintf(stderr, "Found %u %s key%s:\n", key_count, (char *)(isPrivate ? "private" : "public"), (key_count == 1) ? "" : "s"); if (s_slot_key_id && *s_slot_key_id && (key_id_len != 0 || key_label != NULL)) { for (n = 0; n < key_count; n++) { PKCS11_KEY *k = keys + n; if (ctx->verbose) { fprintf(stderr, " %2u %c%c %s\n", n + 1, k->isPrivate ? 'P' : ' ', k->needLogin ? 'L' : ' ', k->label); } if (key_label == NULL) { if (key_id_len != 0 && k->id_len == key_id_len && memcmp(k->id, key_id, key_id_len) == 0) { selected_key = k; } } else { if (strcmp(k->label, key_label) == 0) { selected_key = k; } } } } else { selected_key = keys; /* Use the first key */ } if (selected_key == NULL) { fprintf(stderr, "Key not found.\n"); return NULL; } pk = isPrivate ? PKCS11_get_private_key(selected_key) : PKCS11_get_public_key(selected_key); if (key_label != NULL) OPENSSL_free(key_label); return pk; }
PKI_MEM_STACK *URL_get_data_pkcs11_url ( URL *url, ssize_t size ) { #ifdef HAVE_P11 // PKCS11_CTX *ctx = NULL; PKCS11_SLOT *slots = NULL; PKCS11_TOKEN *tk = NULL; char *libfile = NULL; int num = 0; int i = 0; char * search_label = NULL; char * search_id = NULL; char * search_slot = NULL; char * search_slotid = NULL; PKI_MEM *tmp_mem = NULL; PKI_MEM_STACK *sk = NULL; if( !url ) return (NULL); /* if((libfile = pkcs11_parse_url_libpath ( url )) == NULL ) { return( NULL ); } */ /* slot = pkcs11_parse_url_slot ( url ); id = pkcs11_parse_url_id ( url ); */ if( ctx == NULL ) { if((ctx = PKCS11_CTX_new ()) == NULL ) { return(NULL); } PKI_log_debug("Loading %s Library", url->addr ); if(( i = PKCS11_CTX_load(ctx, url->addr)) != 0 ) { PKI_log_err("Can not load library %s [err::%d]", url->addr, i); // ERR_print_errors_fp( stderr ); } } if( PKCS11_enumerate_slots( ctx, &slots, &num ) == -1 ) { PKI_log_err ("Can not enumerate slots"); goto err; }; if(( sk = PKI_STACK_MEM_new()) == NULL ) { goto err; } search_slot = pkcs11_parse_url_getval( url, "slot" ); search_slotid = pkcs11_parse_url_getval( url, "slotid" ); search_label = pkcs11_parse_url_getval( url, "label" ); search_id = pkcs11_parse_url_getval( url, "id" ); if( search_slot ) PKI_log_debug("DEBUG::PKCS11::SEARCH::SLOT => %s\n", search_slot); if( search_slotid ) PKI_log_debug("DEBUG::PKCS11::SEARCH::SLOTID => %s\n", search_slotid); if( search_label ) PKI_log_debug("DEBUG::PKCS11::SEARCH::LABEL => %s\n", search_label); if( search_id ) PKI_log_debug("DEBUG::PKCS11::SEARCH::ID => %s\n", search_id); for(i = 0; i < num; i++ ) { BIO *mem = NULL; BUF_MEM *mem_buf = NULL; PKCS11_CERT *certs = NULL; PKCS11_SLOT *p = NULL; PKCS11_CERT *x = NULL; PKCS11_KEY *keyList = NULL; PKCS11_KEY *key = NULL; EVP_PKEY *evp_pkey = NULL; int n = 0; int t = 0; int n_objs = 0; int p_ret = 0; p = &slots[i]; if((!p) || ((tk = p->token) == NULL) ) { continue; } if( (search_slot) && ( strncmp_nocase( search_slot, tk->label, strlen(search_slot) == 0) )) { continue; } if( (search_slotid) && ( atoi(search_slotid) != i )) { PKI_log_debug("PKCS11::SLOTID is %s (%d), curr is %d\n", search_slotid, atoi(search_slotid), i); continue; } if( strncmp_nocase( url->attrs, "cert", 4 ) == 0) { PKI_log_debug("PKCS11::CERT DATATYPE SELECTED!\n"); if((mem = BIO_new(BIO_s_mem())) == NULL ) { goto err; } /* Get the list of certificates in the slot */ p_ret = PKCS11_enumerate_certs( tk, &certs, &n_objs); for( n = 0; n < n_objs; n++ ) { /* Pointer to the current certificate */ x = &certs[n]; PKI_log_debug("PKCS11::CERT label=%s\n", x->label); PKI_log_debug("PKCS11::CERT id="); for( t = 0; t < x->id_len; t ++ ) { printf("%c", x->id[t] ); } printf("\n"); if( (search_label) && (strncmp_nocase( search_label, x->label, strlen( search_label)) != 0 )){ PKI_log_debug("PKCS11::LABEL does not" "match, SKIPPING!!!!\n"); continue; } if( search_id ) { int stop = 0; for( t = 0; t < x->id_len; t ++ ) { if( search_id[t] != x->id[t] ) { stop = 1; break; } } if( stop == 1 ) { printf("DEBUG::PKCS11::ID does not" "match, SKIPPING!!!!\n"); continue; } } /* Write the cert in PEM format to memory */ p_ret = PEM_write_bio_X509( mem, x->x509 ); /* Get the pointer to the memory buffer */ BIO_get_mem_ptr( mem, &mem_buf ); /* Push a PKI_MEM buffer on the stack */ tmp_mem = PKI_MEM_new_null(); PKI_MEM_add ( tmp_mem, mem_buf->data, mem_buf->length); PKI_STACK_push( sk, tmp_mem ); } /* Free the temp memory buffer */ if( mem ) BIO_free( mem ); } else if (strncmp_nocase( url->attrs, "key", 3) == 0 ) { char *pin = NULL; PKI_log_debug("PKCS11::KEY DATATYPE SELECTED!\n"); pin = pkcs11_parse_url_getval( url, "pin" ); if ( (tk->loginRequired == 1) && (pin != NULL ) ) { p_ret = PKCS11_login ( p, 0, pin ); PKI_log_debug("PKCS11::LOGIN Result %d\n", p_ret ); } if((mem = BIO_new(BIO_s_mem())) == NULL ) { goto err; } p_ret = PKCS11_enumerate_keys ( tk, &keyList, &n_objs ); for( n = 0; n < n_objs; n++ ) { key = &keyList[n]; printf("DEBUG::PKCS11::KEY label=%s\n", key->label); printf("DEBUG::PKCS11::KEY id="); for( t = 0; t < key->id_len; t ++ ) { printf("%c", key->id[t] ); } printf("\n"); if( (search_label) && (strncmp_nocase( search_label, x->label, strlen( search_label)) != 0 )){ printf("DEBUG::PKCS11::LABEL does not" "match, SKIPPING!!!!\n"); continue; } if( search_id ) { int stop = 0; for( t = 0; t < x->id_len; t ++ ) { if( search_id[t] != x->id[t] ) { stop = 1; break; } } if( stop == 1 ) { printf("DEBUG::PKCS11::ID does not" "match, SKIPPING!!!!\n"); continue; } } /* Get Private Key in OpenSSL format */ evp_pkey = PKCS11_get_private_key( key ); /* Write the cert in PEM format to memory */ p_ret = PEM_write_bio_PUBKEY( mem, evp_pkey ); /* Get the pointer to the memory buffer */ BIO_get_mem_ptr( mem, &mem_buf ); /* Push a PKI_MEM buffer on the stack */ tmp_mem = PKI_MEM_new_null(); PKI_MEM_add ( tmp_mem, mem_buf->data, mem_buf->length); PKI_STACK_push( sk, tmp_mem ); } if( mem ) BIO_free ( mem ); } else { printf("DEBUG::PKCS11::OTHER DATATYPE SELECTED!\n"); } } err: if( slots ) PKCS11_release_all_slots( ctx, slots, num ); /* if( ctx ) { PKCS11_CTX_unload(ctx); PKCS11_CTX_free(ctx); } */ if( libfile ) PKI_Free (libfile); if( search_slot ) PKI_Free ( search_slot ); if( search_slotid ) PKI_Free ( search_slotid ); if( search_label ) PKI_Free ( search_label ); if( search_id ) PKI_Free ( search_id ); return ( sk ); #else return ( NULL ); #endif }