diff --git a/doc/man-sections/pkcs11-options.rst b/doc/man-sections/pkcs11-options.rst index dfc27af333b..66a66a7ad5d 100644 --- a/doc/man-sections/pkcs11-options.rst +++ b/doc/man-sections/pkcs11-options.rst @@ -83,3 +83,15 @@ PKCS#11 / SmartCard options ``--verb`` option can be used BEFORE this option to produce debugging information. + +--pkcs11-pin pin + Specify the file with the PIN for the PKCS#11 token. + + Valid syntax: + :: + + pkcs11-pin file.txt + + If the PIN is specified from file, the file should contain only the PIN, + without any additional characters. + When ``--pkcs11-pin`` is not specified, the user will be prompted to enter the PIN. diff --git a/src/openvpn/init.c b/src/openvpn/init.c index 187c0a9785a..1c3069ec814 100644 --- a/src/openvpn/init.c +++ b/src/openvpn/init.c @@ -760,7 +760,7 @@ context_init_1(struct context *c) if (c->first_time) { int i; - pkcs11_initialize(true, c->options.pkcs11_pin_cache_period); + pkcs11_initialize(true, c->options.pkcs11_pin_cache_period, c->options.pkcs11_pin_file); for (i = 0; ioptions.pkcs11_providers[i] != NULL; i++) { pkcs11_addProvider(c->options.pkcs11_providers[i], c->options.pkcs11_protected_authentication[i], diff --git a/src/openvpn/options.c b/src/openvpn/options.c index 02970a764cf..c0063016613 100644 --- a/src/openvpn/options.c +++ b/src/openvpn/options.c @@ -693,6 +693,7 @@ static const char usage_message[] = " cache until token is removed.\n" "--pkcs11-id-management : Acquire identity from management interface.\n" "--pkcs11-id serialized-id 'id' : Identity to use, get using standalone --show-pkcs11-ids\n" + "--pkcs11-pin file : File containing the PIN for the PKCS#11 token.\n" #endif /* ENABLE_PKCS11 */ "\n" "SSL Library information:\n" @@ -4153,6 +4154,14 @@ options_postprocess_filechecks(struct options *options) errs |= check_file_access_chroot(options->chroot_dir, CHKACC_FILE, options->tmp_dir, R_OK|W_OK|X_OK, "Temporary directory (--tmp-dir)"); +#ifdef ENABLE_PKCS11 + if (options->pkcs11_pin_file) + { + errs |= check_file_access(CHKACC_FILE|CHKACC_ACPTSTDIN|CHKACC_PRIVATE, + options->pkcs11_pin_file, R_OK, "--pkcs11-pin"); + } +#endif + if (errs) { msg(M_USAGE, "Please correct these errors."); @@ -9444,6 +9453,18 @@ add_option(struct options *options, VERIFY_PERMISSION(OPT_P_GENERAL); options->pkcs11_id_management = true; } + else if (streq(p[0], "pkcs11-pin") && p[1] && !p[2]) + { + VERIFY_PERMISSION(OPT_P_GENERAL); + if (p[1]) + { + options->pkcs11_pin_file = p[1]; + } + else + { + options->pkcs11_pin_file = NULL; + } + } #endif /* ifdef ENABLE_PKCS11 */ else if (streq(p[0], "rmtun") && !p[1]) { diff --git a/src/openvpn/options.h b/src/openvpn/options.h index 8d1ef6c3475..b2ff1d2a894 100644 --- a/src/openvpn/options.h +++ b/src/openvpn/options.h @@ -633,6 +633,7 @@ struct options int pkcs11_pin_cache_period; const char *pkcs11_id; bool pkcs11_id_management; + const char *pkcs11_pin_file; #endif #ifdef ENABLE_CRYPTOAPI diff --git a/src/openvpn/pkcs11.c b/src/openvpn/pkcs11.c index 37cc1678196..7b9e330c1b9 100644 --- a/src/openvpn/pkcs11.c +++ b/src/openvpn/pkcs11.c @@ -40,6 +40,15 @@ #include "console.h" #include "pkcs11_backend.h" + +struct pkcs11_context { + int nPINCachePeriod; + struct user_pass token_pass; + const char *pin_file; +}; + +static struct pkcs11_context pkcs11_ctx; /* GLOBAL */ + static time_t __mytime(void) @@ -181,6 +190,43 @@ _pkcs11_openvpn_log( msg(_pkcs11_msg_pkcs112openvpn(flags), "%s", Buffer); } +static +PKCS11H_BOOL +pkcs11_password_setup( + const char *pkcs11_pin_file, + struct user_pass *token_pass + ) +{ + if (!token_pass) + { + return false; + } + if (pkcs11_pin_file) + { + msg(M_INFO, "pkcs11_password_setup - pkcs11_pin_file='%s'", pkcs11_pin_file); + } + else + { + /* If pin file is not provided, clear the token_pass and continue */ + CLEAR(token_pass); + return true; + } + token_pass->defined = false; + token_pass->nocache = true; + + if (!strlen(token_pass->password)) + { + get_user_pass( + token_pass, + pkcs11_pin_file, + UP_TYPE_PRIVATE_KEY, + GET_USER_PASS_MANAGEMENT|GET_USER_PASS_PASSWORD_ONLY + ); + } + + return true; +} + static PKCS11H_BOOL _pkcs11_openvpn_token_prompt( @@ -236,11 +282,15 @@ _pkcs11_openvpn_pin_prompt( const size_t pin_max ) { - struct user_pass token_pass; char prompt[1024]; - CLEAR(token_pass); + struct pkcs11_context *ctx = NULL; + + if (!global_data) + { + return false; + } + ctx = (struct pkcs11_context *)global_data; - (void)global_data; (void)user_data; (void)retry; @@ -248,12 +298,13 @@ _pkcs11_openvpn_pin_prompt( snprintf(prompt, sizeof(prompt), "%s token", token->label); - token_pass.defined = false; - token_pass.nocache = true; + ctx->token_pass.defined = false; + ctx->token_pass.nocache = true; if ( - !get_user_pass( - &token_pass, + !strlen(ctx->token_pass.password) + && !get_user_pass( + &ctx->token_pass, NULL, prompt, GET_USER_PASS_MANAGEMENT|GET_USER_PASS_PASSWORD_ONLY|GET_USER_PASS_NOFATAL @@ -264,8 +315,8 @@ _pkcs11_openvpn_pin_prompt( } else { - strncpynt(pin, token_pass.password, pin_max); - purge_user_pass(&token_pass, true); + strncpynt(pin, ctx->token_pass.password, pin_max); + purge_user_pass(&ctx->token_pass, true); if (strlen(pin) == 0) { @@ -281,16 +332,24 @@ _pkcs11_openvpn_pin_prompt( bool pkcs11_initialize( const bool protected_auth, - const int nPINCachePeriod + const int nPINCachePeriod, + const char *pin_file ) { CK_RV rv = CKR_FUNCTION_FAILED; + pkcs11_ctx.nPINCachePeriod = nPINCachePeriod; dmsg( D_PKCS11_DEBUG, "PKCS#11: pkcs11_initialize - entered" ); + if (!pkcs11_password_setup(pin_file, &pkcs11_ctx.token_pass)) + { + msg(M_FATAL, "PKCS#11: Cannot initialize pkcs11 password"); + return false; + } + if ((rv = pkcs11h_engine_setSystem(&s_pkcs11h_sys_engine)) != CKR_OK) { msg(M_FATAL, "PKCS#11: Cannot initialize system engine %ld-'%s'", rv, pkcs11h_getMessage(rv)); @@ -317,13 +376,13 @@ pkcs11_initialize( goto cleanup; } - if ((rv = pkcs11h_setTokenPromptHook(_pkcs11_openvpn_token_prompt, NULL)) != CKR_OK) + if ((rv = pkcs11h_setTokenPromptHook(_pkcs11_openvpn_token_prompt, &pkcs11_ctx)) != CKR_OK) { msg(M_FATAL, "PKCS#11: Cannot set hooks %ld-'%s'", rv, pkcs11h_getMessage(rv)); goto cleanup; } - if ((rv = pkcs11h_setPINPromptHook(_pkcs11_openvpn_pin_prompt, NULL)) != CKR_OK) + if ((rv = pkcs11h_setPINPromptHook(_pkcs11_openvpn_pin_prompt, &pkcs11_ctx)) != CKR_OK) { msg(M_FATAL, "PKCS#11: Cannot set hooks %ld-'%s'", rv, pkcs11h_getMessage(rv)); goto cleanup; diff --git a/src/openvpn/pkcs11.h b/src/openvpn/pkcs11.h index 772fa4ed783..8f1789fae9c 100644 --- a/src/openvpn/pkcs11.h +++ b/src/openvpn/pkcs11.h @@ -31,7 +31,8 @@ bool pkcs11_initialize( const bool fProtectedAuthentication, - const int nPINCachePeriod + const int nPINCachePeriod, + const char *pin_file ); void diff --git a/tests/unit_tests/openvpn/test_pkcs11.c b/tests/unit_tests/openvpn/test_pkcs11.c index 3fe3e460758..3949e67526c 100644 --- a/tests/unit_tests/openvpn/test_pkcs11.c +++ b/tests/unit_tests/openvpn/test_pkcs11.c @@ -321,7 +321,7 @@ setup_pkcs11(void **state) /* set default propq as we do in ssl_openssl.c */ EVP_set_default_properties(tls_libctx, "?provider!=ovpn.xkey"); #endif - pkcs11_initialize(true, 0); /* protected auth enabled, pin-cache = 0 */ + pkcs11_initialize(true, 0, NULL); /* protected auth enabled, pin-cache = 0, pin_file = NULL */ pkcs11_addProvider(SOFTHSM2_MODULE_PATH, false, 0, false); return 0; }