int main(int argc, char *argv[]) { PKCS11_CTX *ctx; PKCS11_SLOT *slots, *slot; PKCS11_CERT *certs; PKCS11_KEY *authkey; PKCS11_CERT *authcert; EVP_PKEY *pubkey = NULL; unsigned char *random = NULL, *signature = NULL; char password[20]; int rc = 0, fd; unsigned int nslots, ncerts, siglen; if (argc < 2) { fprintf(stderr, "usage: %s /usr/lib/opensc-pkcs11.so [PIN]\n", argv[0]); return 1; } do_fork(); ctx = PKCS11_CTX_new(); error_queue("PKCS11_CTX_new"); /* load pkcs #11 module */ do_fork(); rc = PKCS11_CTX_load(ctx, argv[1]); error_queue("PKCS11_CTX_load"); if (rc) { fprintf(stderr, "loading pkcs11 engine failed: %s\n", ERR_reason_error_string(ERR_get_error())); rc = 1; goto nolib; } /* get information on all slots */ do_fork(); rc = PKCS11_enumerate_slots(ctx, &slots, &nslots); error_queue("PKCS11_enumerate_slots"); if (rc < 0) { fprintf(stderr, "no slots available\n"); rc = 2; goto noslots; } /* get first slot with a token */ do_fork(); slot = PKCS11_find_token(ctx, slots, nslots); error_queue("PKCS11_find_token"); if (slot == NULL || slot->token == NULL) { fprintf(stderr, "no token available\n"); rc = 3; goto notoken; } printf("Slot manufacturer......: %s\n", slot->manufacturer); printf("Slot description.......: %s\n", slot->description); printf("Slot token label.......: %s\n", slot->token->label); printf("Slot token manufacturer: %s\n", slot->token->manufacturer); printf("Slot token model.......: %s\n", slot->token->model); printf("Slot token serialnr....: %s\n", slot->token->serialnr); if (!slot->token->loginRequired) goto loggedin; /* get password */ if (argc > 2) { strcpy(password, argv[2]); } else { exit(1); } loggedin: /* perform pkcs #11 login */ do_fork(); rc = PKCS11_login(slot, 0, password); error_queue("PKCS11_login"); memset(password, 0, strlen(password)); if (rc != 0) { fprintf(stderr, "PKCS11_login failed\n"); goto failed; } /* get all certs */ do_fork(); rc = PKCS11_enumerate_certs(slot->token, &certs, &ncerts); error_queue("PKCS11_enumerate_certs"); if (rc) { fprintf(stderr, "PKCS11_enumerate_certs failed\n"); goto failed; } if (ncerts <= 0) { fprintf(stderr, "no certificates found\n"); goto failed; } /* use the first cert */ authcert=&certs[0]; /* get random bytes */ random = OPENSSL_malloc(RANDOM_SIZE); if (random == NULL) goto failed; fd = open(RANDOM_SOURCE, O_RDONLY); if (fd < 0) { fprintf(stderr, "fatal: cannot open RANDOM_SOURCE: %s\n", strerror(errno)); goto failed; } rc = read(fd, random, RANDOM_SIZE); if (rc < 0) { fprintf(stderr, "fatal: read from random source failed: %s\n", strerror(errno)); close(fd); goto failed; } if (rc < RANDOM_SIZE) { fprintf(stderr, "fatal: read returned less than %d<%d bytes\n", rc, RANDOM_SIZE); close(fd); goto failed; } close(fd); do_fork(); authkey = PKCS11_find_key(authcert); error_queue("PKCS11_find_key"); if (authkey == NULL) { fprintf(stderr, "no key matching certificate available\n"); goto failed; } /* ask for a sha1 hash of the random data, signed by the key */ siglen = MAX_SIGSIZE; signature = OPENSSL_malloc(MAX_SIGSIZE); if (signature == NULL) goto failed; /* do the operations in child */ do_fork(); rc = PKCS11_sign(NID_sha1, random, RANDOM_SIZE, signature, &siglen, authkey); error_queue("PKCS11_sign"); if (rc != 1) { fprintf(stderr, "fatal: pkcs11_sign failed\n"); goto failed; } /* verify the signature */ pubkey = X509_get_pubkey(authcert->x509); if (pubkey == NULL) { fprintf(stderr, "could not extract public key\n"); goto failed; } /* now verify the result */ rc = RSA_verify(NID_sha1, random, RANDOM_SIZE, signature, siglen, pubkey->pkey.rsa); if (rc != 1) { fprintf(stderr, "fatal: RSA_verify failed\n"); goto failed; } if (pubkey != NULL) EVP_PKEY_free(pubkey); if (random != NULL) OPENSSL_free(random); if (signature != NULL) OPENSSL_free(signature); PKCS11_release_all_slots(ctx, slots, nslots); PKCS11_CTX_unload(ctx); PKCS11_CTX_free(ctx); CRYPTO_cleanup_all_ex_data(); ERR_free_strings(); printf("authentication successfull.\n"); return 0; failed: notoken: PKCS11_release_all_slots(ctx, slots, nslots); noslots: PKCS11_CTX_unload(ctx); nolib: PKCS11_CTX_free(ctx); printf("authentication failed.\n"); return 1; }
/** * Signs the digest provided using the selected certificate. If the certificate needs PIN, * the PIN is acquired by calling the callback function <code>getPin</code>. * * @param digest digest, which is being signed. * @param signature memory for the signature that is created. Struct parameter <code>length</code> * is set to the actual signature length. * @throws SignException throws exception if the signing operation failed. */ void digidoc::PKCS11Signer::sign(const Digest& digest, Signature& signature) throw(SignException) { DEBUG("sign(digest = {type=%s,digest=%p,length=%d}, signature={signature=%p,length=%d})", OBJ_nid2sn(digest.type), digest.digest, digest.length, signature.signature, signature.length); // Check that sign slot and certificate are selected. if(d->sign.certificate == NULL || d->sign.slot == NULL) { THROW_SIGNEXCEPTION("Signing slot or certificate are not selected."); } // Login if required. if(d->sign.slot->token->loginRequired) { int rv = 0; if(d->sign.slot->token->secureLogin) { showPinpad(); rv = PKCS11_login(d->sign.slot, 0, NULL); hidePinpad(); } else rv = PKCS11_login(d->sign.slot, 0, getPin(d->createPKCS11Cert(d->sign.slot, d->sign.certificate)).c_str()); switch(ERR_GET_REASON(ERR_get_error())) { case CKR_OK: break; case CKR_CANCEL: case CKR_FUNCTION_CANCELED: { SignException e( __FILE__, __LINE__, "PIN acquisition canceled."); e.setCode( Exception::PINCanceled ); throw e; break; } case CKR_PIN_INCORRECT: { SignException e( __FILE__, __LINE__, "PIN Incorrect" ); e.setCode( Exception::PINIncorrect ); throw e; break; } case CKR_PIN_LOCKED: { SignException e( __FILE__, __LINE__, "PIN Locked" ); e.setCode( Exception::PINLocked ); throw e; break; } default: std::ostringstream s; s << "Failed to login to token '" << d->sign.slot->token->label << "': " << ERR_reason_error_string(ERR_get_error()); SignException e( __FILE__, __LINE__, s.str() ); e.setCode( Exception::PINFailed ); throw e; break; } } PKCS11_KEY* signKey = PKCS11_find_key(d->sign.certificate); if(signKey == NULL) { THROW_SIGNEXCEPTION("Could not get key that matches selected certificate."); } // Sign the digest. int result = PKCS11_sign(digest.type, digest.digest, digest.length, signature.signature, &(signature.length), signKey); if(result != 1) { THROW_SIGNEXCEPTION("Failed to sign digest: %s", ERR_reason_error_string(ERR_get_error())); } }