Message ID | 20181031165954.6139-1-arne@rfc2549.org |
---|---|
State | Superseded |
Headers | show |
Series | [Openvpn-devel] Add support for OpenSSL TLS 1.3 when using management-external-key | expand |
Hi, My comments below has grown too long so first a summary for those who TLDR; My suggestion: - Leave management-external-key as is (there is not much gained by adding a parameter to it) - Append a fairly flexible signature algorithm specifier to PK_SIGN request to management (nopadding or pkcs1 is not good enough in the long run) Do not take cue from OpenSSL's design of RSA_private_encrypt() and rsa_sign() both of which fall short for historic reasons. - require version 3 clients to support at least certain algorithms Some of the comments below were written assuming --management-external-key will get a new optional parameter and some are based on my suggestion not to do so. So the rest is sometimes a bit of flux and/or repetitive. But I spent some time on this so here goes: On Wed, Oct 31, 2018 at 1:00 PM Arne Schwabe <arne@rfc2549.org> wrote: > > For TLS 1.0 to 1.2 and OpenSSL 1.1.0 calls us and requires a PKCS1 > padded response. As TLS 1.3 mandates RSA-PSS padding support and also > requires an TLS 1.3 implementation to support RSA-PSS for older TLS > version, OpenSSL will query us to sign an already RSA-PSS padded > string. > > This patch adds an 'unpadded' and 'pkcs1' parameter to the > > management-external-key option to signal that the client is > able to support pkcs1 as well as unpadded signature requests. "unpadded" in past tense is confusing -- I suggest "nopadding" or "raw" or "rsa-raw" to indicate that what it expects to do is a raw signature (or no padding will be added) which means the caller should do the padding. In such cases the input will be invariably of the same size as the modulus and there is no room for padding anyway. (NB: in the code proper, you do use "nopadding" and not "unpadded" which is better -- but also see below) That said, I still fail to warm up to the idea of adding a parameter to management-external-key. First, even with this precaution, signing can fail in two cases: (i) the config file has "--management-external-key nopadding" but the client version is <= 2. In such cases no warning will be printed but management will get prepadded data with no ALG indicator which the external signer will definitely fail to treat as PKCS1. Either signing will fail (not sure how an existing client would handle that) or connection will restart with verification error. (ii) Taking a long view, the real problem is not just "padding" but "signature algorithm" in general. That is, PK_SIGN (or RSA_SIGN) does not provide enough details for generating a signature. In good old days when we supported only TLS 1.1 or older and RSA keys, there was only one kind of signature. Today one needs to know the hash algorithm and the padding scheme to generate a signature. We get away without the hash algorithm as the digestinfo header is prepended to the hash by the time rsa_priv_enc is called (not so in mbedTLS so we add it in that handler). But that will not work for PSS if we were to support external PSS padding -- which we should do in the long term. Part of the reason for this is we have been playing along with OpenSSL which has been trying hard to preserve a dated API. Now with 1.1.1, they have broken it for good and the rsa_sign() callback does not even get called anymore as padding cannot be assumend to be PKCS1. So we have to stop taking cue from OpenSSL especially since the purpose of external key is to support arbitrary external signing agents/libraries. So, in short, I suggest to just leave the management-external-key option alone and only add a new parameter to PK_SIGN (more on that below) and make sure the external sign dispatcher does not error out when padding is not PKCS1 (ie. support at least RSA_PADDING_NONE and RSA_PADDING_PKCS1 in rsa_priv_enc() for now) The early erroring out is only marginally useful as it does not catch all cases as argued above. Also a user may try to deal with the error by setting tls version max to 1.2 but that will also fail when openssl 1.1.1 is use -- this time without triggering the early error-out. So we gain little by mutilating this option and all the complications it brings. The patch will be considerably simple once this change is taken out. In any case, both here (if we retain this) and in PK_SIGN a more generic signalling is required. Else we wont be able to support external PSS padding later -- just padding = PSS is not enough to do that, the hash algorithm is also required. The same is true for PKCS1 too but currently we do not support external signer to add digest info for PKCS1 signatures. But going forward, some external signers would need that option. I would suggest: PKS_SIGN <base64data>,ALG where ALG = RSA_NONE_PKCS1 (current default), RSA_RAW (or RSA_NONE_NOPADDING) RSA_<hash-alg>_PKCS1 ECDSA (current default if key is EC) with ALG missing to be interpreted as current defaults (PKCS1 with digest info already prepended for RSA and ECDSA for EC). Here <hash_lag> could be SHA256, SHA1 etc. and indicates that the data is just the hash and the signer should add digestinfo header to the signature. We do not have to support this as yet but will come handy to have a way to do a complete signature algorithm specifier in ALG. And require that version 3 clients are expected to support at least RSA_NONE_PKCS1, RSA_RAW and ECDSA. Anyway, I did review the code considering both options -- not all comments below are relevant if we decide not to modify --management-external-key. That would be my preference. > > Since clients that implement the management-external-key interface > are usually rather tightly integrated solutions (OpenVPN Connect in the > past, OpenVPN for Android), it is reasonable to expect that > upgrading the OpenSSL library can be done together with > management interface changes. Therefore we provide no backwards > compatbility for mangement-interface clients not supporting > OpenSSL 1.1.1. Looks perfectly acceptable to me.. > > > Using the management api client version instead might seem like the > more logical way but since we only now that version very late, > it would extra logic and complexity to deal with this asynchronous > behaviour. Instead just give an error early if OpenSSL 1.1.1 and > management-external-key without nopadding is detected. > > The interface is prepared for signalling PCKS1 and RSA-PSS support > instead of signalling unpadded support. "instead of" --> "in addition to" ? unpadded support --> "signature algorithm to use" > > > Patch v3: fix overlong lines and few other style patches. Note > two overlong lines concerning mbedtls are not fixed as they > are removed/shortend by the mbed tls patch to avoid conflicts > > Patch v4: Setting minimum TLS version proved to be not enough and > instead of implementing a whole compability layer we require > mangement-clients to implement the new feature when they want > to use OpenSSL 1.1.1 > > Add a padding=ALGORITHM argument to pk-sig to indicate the > algorithm. Drop adding PKCS1 ourselves. The code below adds ",ALG" to PK_SIGN, not padding=ALG to pk-sig. Better make the above consistent with that. > > > Patch v5: Send the right version of the patch > > Signed-off-by: Arne Schwabe <arne@rfc2549.org> > --- > doc/management-notes.txt | 13 ++++++++++- > doc/openvpn.8 | 7 ++++-- > src/openvpn/manage.c | 18 +++++++++++--- > src/openvpn/manage.h | 23 +++++++++++------- > src/openvpn/options.c | 45 +++++++++++++++++++++++++++++++++-- > src/openvpn/ssl_mbedtls.c | 7 ++++-- > src/openvpn/ssl_openssl.c | 49 +++++++++++++++++++++++++++++++-------- > 7 files changed, 134 insertions(+), 28 deletions(-) > > diff --git a/doc/management-notes.txt b/doc/management-notes.txt > index 17645c1d..f685af28 100644 > --- a/doc/management-notes.txt > +++ b/doc/management-notes.txt > @@ -816,6 +816,7 @@ actual private key. When the SSL protocol needs to perform a sign > operation, the data to be signed will be sent to the management interface > via a notification as follows: > > +>PK_SIGN:[BASE64_DATA],[ALG] (if client announces support for management version > 2) > >PK_SIGN:[BASE64_DATA] (if client announces support for management version > 1) > >RSA_SIGN:[BASE64_DATA] (only older clients will be prompted like this) List values of ALG that a version 3 client should support. And add that if ALG is missing it should be interpreted as ECDSA for EC keys and RSA_NONE_PKCS1 for RSA keys. That nicely covers the two possible forms of PK_SIGN directive. > > > @@ -823,7 +824,7 @@ The management interface client should then create an appropriate signature of > the (decoded) BASE64_DATA using the private key and return the SSL signature as > follows: > > -pk-sig (or rsa-sig) > +pk-sig (or rsa-sig) > [BASE64_SIG_LINE] > . > . > @@ -833,6 +834,12 @@ END > Base 64 encoded output of RSA_private_encrypt for RSA or ECDSA_sign() > for EC using OpenSSL or mbedtls_pk_sign() using mbed TLS will provide a > correct signature. > +The rsa-sig interfaces expects PKCS1 padded signatures for RSA keys > +(RSA_PKCS1_PADDING). EC signatures are always unpadded. > > + > +The padding field is only present when pk-sig is used and > +currently the following values can be requested PCKS1 and NOPADDING for RSA > +certificates and NOPADDING for EC certificates. This is totally confusing. There is no reason to distinguish between rsa-sig and pk-sig as used by the client although we should encourage all new clients to use pk-sig only. These added lines may be replaced by: "For RSA keys, if signature algorithm is "RSA_NONE_PKCS1" or unspecified, the data to sign contains the hash with digest info header added. If the algorithm is RSA_RAW, a raw RSA sign operation should be performed. Base 64 encoded output of OpenSSL function RSA_private_encrypt() with padding=RSA_PADDING_PKCS1 for the first case and padding=RSA_PADDING_NONE in the second case creates the correct signature. In case of EC keys Base 64 encoded output of ECDSA_sign() provides the correct signature." And remove those references to ECDSA_sign() and RSA_private_encrypt() earlier. > > > This capability is intended to allow the use of arbitrary cryptographic > service providers with OpenVPN via the management interface. > @@ -840,6 +847,10 @@ service providers with OpenVPN via the management interface. > New and updated clients are expected to use the version command to announce > a version > 1 and handle '>PK_SIGN' prompt and respond with 'pk-sig'. > > +The older rsa-sig and pk-sig interfaces hav no capability to indidicate the > +requested padding algorithm. When the 'nopadding' using version >= 2 is required. > +To support TLS 1.3 with OpenSSL 1.1.1 supporting unpadded signatures is required. > + Again, confusing. If you want to reiterate this what about: "The signature algorithm is indicated in the PK_SIGN request only if the or management client-version is > 2. In particular, to support TLS1.3 and TLS1.2 using OpenSSL 1.1.1, non-pkcs1 padded signature support is required and this can be indicated in the signing request only if the client version is > 2." > COMMAND -- certificate (OpenVPN 2.4 or higher) > ---------------------------------------------- > Provides support for external storage of the certificate. Requires the > diff --git a/doc/openvpn.8 b/doc/openvpn.8 > index e80d4696..3cd5d944 100644 > --- a/doc/openvpn.8 > +++ b/doc/openvpn.8 > @@ -2739,10 +2739,13 @@ Allow management interface to override > directives (client\-only). > .\"********************************************************* > .TP > -.B \-\-management\-external\-key > +.B \-\-management\-external\-key [nopadding] [pkcs1] > Allows usage for external private key file instead of > .B \-\-key > -option (client\-only). > +option (client\-only). The optional parameters nopadding and > +pkcs1 signal support for different padding algorithms. See > +doc/mangement-notes.txt for a complete description of this > +feature. > .\"********************************************************* > .TP > .B \-\-management\-external\-cert certificate\-hint > diff --git a/src/openvpn/manage.c b/src/openvpn/manage.c > index 8b633f20..62d4bc7b 100644 > --- a/src/openvpn/manage.c > +++ b/src/openvpn/manage.c > @@ -3639,18 +3639,30 @@ management_query_multiline_flatten(struct management *man, > > char * > /* returns allocated base64 signature */ > -management_query_pk_sig(struct management *man, > - const char *b64_data) > +management_query_pk_sig(struct management *man, const char *b64_data, > + const char *padding) Suggest to change padding -> sign_alg > > { > const char *prompt = "PK_SIGN"; > const char *desc = "pk-sign"; > + struct buffer buf_data = alloc_buf(strlen(b64_data) + strlen(padding) + 20); > + > if (man->connection.client_version <= 1) > { > prompt = "RSA_SIGN"; > desc = "rsa-sign"; > } > - return management_query_multiline_flatten(man, b64_data, prompt, desc, > + > + buf_write(&buf_data, b64_data, (int) strlen(b64_data)); > + if (man->connection.client_version > 2) > > + { > + buf_write(&buf_data, ",", (int) strlen(",")); > + buf_write(&buf_data, padding, (int) strlen(padding)); > + } > + char* ret = management_query_multiline_flatten(man, > + (char *)buf_bptr(&buf_data), prompt, desc, > &man->connection.ext_key_state, &man->connection.ext_key_input); > + free_buf(&buf_data); > + return ret; > } > > char * > diff --git a/src/openvpn/manage.h b/src/openvpn/manage.h > index d24abe09..4bfcfdbe 100644 > --- a/src/openvpn/manage.h > +++ b/src/openvpn/manage.h > @@ -31,7 +31,7 @@ > #include "socket.h" > #include "mroute.h" > > -#define MANAGEMENT_VERSION 2 > +#define MANAGEMENT_VERSION 3 > #define MANAGEMENT_N_PASSWORD_RETRIES 3 > #define MANAGEMENT_LOG_HISTORY_INITIAL_SIZE 100 > #define MANAGEMENT_ECHO_BUFFER_SIZE 100 > @@ -341,12 +341,18 @@ struct management *management_init(void); > #ifdef MANAGEMENT_PF > #define MF_CLIENT_PF (1<<7) > #endif > -#define MF_UNIX_SOCK (1<<8) > -#define MF_EXTERNAL_KEY (1<<9) > -#define MF_UP_DOWN (1<<10) > -#define MF_QUERY_REMOTE (1<<11) > -#define MF_QUERY_PROXY (1<<12) > -#define MF_EXTERNAL_CERT (1<<13) > +#define MF_UNIX_SOCK (1<<8) > +#define MF_EXTERNAL_KEY (1<<9) > +#define MF_EXTERNAL_KEY_NOPADDING (1<<10) > +#define MF_EXTERNAL_KEY_PKCS1PAD (1<<11) > +#define MF_UP_DOWN (1<<12) > +#define MF_QUERY_REMOTE (1<<13) > +#define MF_QUERY_PROXY (1<<14) > +#define MF_EXTERNAL_CERT (1<<15) > + > +#define MF_RSA_PKCS1_PADDING 1 > +#define MF_RSA_NO_PADDING 2 > + These extra defines and associated code can go if --management-external-key is not changed. > > > bool management_open(struct management *man, > const char *addr, > @@ -430,7 +436,8 @@ void management_learn_addr(struct management *management, > > #endif > > -char *management_query_pk_sig(struct management *man, const char *b64_data); > +char *management_query_pk_sig(struct management *man, const char *b64_data, > + const char* pading); pading -> padding for consistency.. But padding -> sign_alg is my preference. > > > char *management_query_cert(struct management *man, const char *cert_name); > > diff --git a/src/openvpn/options.c b/src/openvpn/options.c > index 406669a3..2291dd9d 100644 > --- a/src/openvpn/options.c > +++ b/src/openvpn/options.c > @@ -2141,6 +2141,23 @@ options_postprocess_verify_ce(const struct options *options, const struct connec > > #endif > > +#if defined(ENABLE_CRYPTOAPI) > + if (o->cryptoapi_cert && (tls_version_max() >= TLS_VER_1_3)) > + { > + msg(M_ERR, "Cryptoapi support currently is incompatible " > + "with OpenSSL 1.1.1/TLS 1.3"); > + } TLS1.2 is also affected but for now ok like this. I have a fix to support PSS in cryptoapi, just have to find some time to test it thoroughly. Sigh.. > +#endif > +#if defined(ENABLE_MANAGEMENT) > + if ((tls_version_max() >= TLS_VER_1_3) && > > + (options->management_flags & MF_EXTERNAL_KEY) && > + !(options->management_flags & (MF_EXTERNAL_KEY_NOPADDING)) > > + ) > + { > + msg(M_ERR, "management-external-key with OpenSSL 1.1.1 requires " > + "the nopadding argument/support"); > + } Same as above but I think this check is not that useful.. > > +#endif > /* > * Windows-specific options. > */ > @@ -5151,9 +5168,33 @@ add_option(struct options *options, > options->management_write_peer_info_file = p[1]; > } > #ifdef ENABLE_MANAGEMENT > - else if (streq(p[0], "management-external-key") && !p[1]) > + else if (streq(p[0], "management-external-key")) > { > VERIFY_PERMISSION(OPT_P_GENERAL); > + for (int j = 1; j < MAX_PARMS && p[j] != NULL; ++j) > + { > + if (streq(p[j], "nopadding")) > + { > + options->management_flags |= MF_EXTERNAL_KEY_NOPADDING; > + } > + else if (p[1] && streq(p[1], "pkcs1")) That should be else if (streq(p[j], "pkcs1")) Note the [j] But the whole chunk could be removed.. > > + { > + options->management_flags |= MF_EXTERNAL_KEY_PKCS1PAD; > + } > + else > + { > + msg(msglevel, "Unknown management-external-key flag: %s" , p[j]); > + } > + } > + /* > + * When no option is present, assume that only PKCS1 > + * padding is supported > + */ > + if (! (options->management_flags & > + (MF_EXTERNAL_KEY_NOPADDING | MF_EXTERNAL_KEY_PKCS1PAD))) > + { > + options->management_flags |= MF_EXTERNAL_KEY_PKCS1PAD; > + } As we will anyway prompt for PKCS1 signatures even if the client does not announce it, we can always set that flag unconditionally and assume/require that all clients support PKCS1. Then the above is a simple options->management_flags |= MF_EXTERNAL_KEY_PKCS1PAD Again the above is irrelevant if we go with my suggestion to not touch this option. > options->management_flags |= MF_EXTERNAL_KEY; > } > else if (streq(p[0], "management-external-cert") && p[1] && !p[2]) > @@ -8456,4 +8497,4 @@ add_option(struct options *options, > } > err: > gc_free(&gc); > -} > \ No newline at end of file > +} > diff --git a/src/openvpn/ssl_mbedtls.c b/src/openvpn/ssl_mbedtls.c > index f7e8c2d0..09b1a8fa 100644 > --- a/src/openvpn/ssl_mbedtls.c > +++ b/src/openvpn/ssl_mbedtls.c > @@ -626,7 +626,6 @@ tls_ctx_use_external_signing_func(struct tls_root_ctx *ctx, > } > > #ifdef ENABLE_MANAGEMENT > - > /** Query the management interface for a signature, see external_sign_func. */ > static bool > management_sign_func(void *sign_ctx, const void *src, size_t src_len, > @@ -641,7 +640,11 @@ management_sign_func(void *sign_ctx, const void *src, size_t src_len, > goto cleanup; > } > > - if (!(dst_b64 = management_query_pk_sig(management, src_b64))) > + /* > + * We only use PKCS1 signatures at the moment in mbed TLS, > + * there the signature parameter is hardcoded > + */ > + if (!(dst_b64 = management_query_pk_sig(management, src_b64, "PKCS1"))) PKCS1 --> RSA_NONE_PKCS1 :) > { > goto cleanup; > } > diff --git a/src/openvpn/ssl_openssl.c b/src/openvpn/ssl_openssl.c > index c2c8fdc0..237c2b55 100644 > --- a/src/openvpn/ssl_openssl.c > +++ b/src/openvpn/ssl_openssl.c > @@ -1079,24 +1079,46 @@ openvpn_extkey_rsa_finish(RSA *rsa) > return 1; > } > > -/* Pass the input hash in 'dgst' to management and get the signature back. > +/* > + * Convert OpenSSL's constant to the strings used in the management > + * interface query > + */ > +const char* > +get_sig_padding_name(const int padding) > +{ > + switch(padding) > + { > + case RSA_PKCS1_PADDING: > + return "PKCS1"; > + case RSA_NO_PADDING: > + return "NOPADDING"; > + default: > + return "UNKNOWN"; > + } > +} Change the above to sign_alg_name instead of padding_name > + > +/* > + * Pass the input hash in 'dgst' to management and get the signature back. > * On input siglen contains the capacity of the buffer 'sig'. > * On return signature is in sig. > + * pkcs1 controls if pkcs1 padding is required That should be "The parameter padding controls the type of padding to use." But I suggest sign_alg controls the signature algorithm to use. The caller need only translate padding (not hash algorithm) to signature algorithm as the hash_alg is currently not available in rsa_priv_enc() callback. So for now hash-alg will be always indicated as none. However, we want the management interface protocol be more flexible and hence we indicate the signature algorithm using more descriptive mnemonics like RSA_NONE_PKCS1 etc in PK_SIGN. > * Return value is signature length or -1 on error. > */ > static int > get_sig_from_man(const unsigned char *dgst, unsigned int dgstlen, > - unsigned char *sig, unsigned int siglen) > + unsigned char *sig, unsigned int siglen, > + int padding) I suggest replace that "int padding" by "const char *padding" and pass in the translated name --- see below for a rationale. Actually "const char *sign_alg" is my preference. > > { > char *in_b64 = NULL; > char *out_b64 = NULL; > int len = -1; > > - /* convert 'dgst' to base64 */ > - if (management > - && openvpn_base64_encode(dgst, dgstlen, &in_b64) > 0) > + int bencret = openvpn_base64_encode(dgst, dgstlen, &in_b64); > + > + if (management && bencret > 0) > { > - out_b64 = management_query_pk_sig(management, in_b64); > + out_b64 = management_query_pk_sig(management, in_b64, > + get_sig_padding_name(padding)); Then that would be just padding or sign_alg > > } > if (out_b64) > { > @@ -1110,18 +1132,19 @@ get_sig_from_man(const unsigned char *dgst, unsigned int dgstlen, > > /* sign arbitrary data */ > static int > -rsa_priv_enc(int flen, const unsigned char *from, unsigned char *to, RSA *rsa, int padding) > +rsa_priv_enc(int flen, const unsigned char *from, unsigned char *to, RSA *rsa, > + int padding) > { > unsigned int len = RSA_size(rsa); > int ret = -1; > > - if (padding != RSA_PKCS1_PADDING) > + if (padding != RSA_PKCS1_PADDING && padding != RSA_NO_PADDING) > { > RSAerr(RSA_F_RSA_OSSL_PRIVATE_ENCRYPT, RSA_R_UNKNOWN_PADDING_TYPE); > return -1; > } > > - ret = get_sig_from_man(from, flen, to, len); > + ret = get_sig_from_man(from, flen, to, len, padding); And use "get_sig_padding_name(padding)" or preferably "get_sign_alg_name(padding)" here. > > return (ret == len)? ret : -1; > } > @@ -1215,7 +1238,13 @@ ecdsa_sign(int type, const unsigned char *dgst, int dgstlen, unsigned char *sig, > unsigned int *siglen, const BIGNUM *kinv, const BIGNUM *r, EC_KEY *ec) > { > int capacity = ECDSA_size(ec); > - int len = get_sig_from_man(dgst, dgstlen, sig, capacity); > + /* > + * ECDSA does not seem to have proper constants for paddings since > + * there are only signatures without padding at the moment, reuse > + * RSA_NO_PADDING for now as it will trigger querying for "NOPADDING" in the > + * management interface > + */ > > + int len = get_sig_from_man(dgst, dgstlen, sig, capacity, RSA_NO_PADDING); That comment reads like a hack. As suggested above, passing the padding or sign_alg name avoids it. And one could instead say: /* ECDSA signature involves no padding */ int len = get_sig_from_man(dgst, dgstlen, sig, capacity, "ECDSA"); Just as "PKCS1" (or "RSA_NONE_PKCS1") is hard coded in the request when using mbedTLS. > > > if (len > 0) > { > -- > 2.19.1 Selva
>> For TLS 1.0 to 1.2 and OpenSSL 1.1.0 calls us and requires a PKCS1 >> padded response. As TLS 1.3 mandates RSA-PSS padding support and also >> requires an TLS 1.3 implementation to support RSA-PSS for older TLS >> version, OpenSSL will query us to sign an already RSA-PSS padded >> string. >> >> This patch adds an 'unpadded' and 'pkcs1' parameter to the >> >> management-external-key option to signal that the client is >> able to support pkcs1 as well as unpadded signature requests. > > > "unpadded" in past tense is confusing -- I suggest "nopadding" or "raw" or > "rsa-raw" to indicate that what it expects to do is a raw signature > (or no padding will be added) which means the caller should do the padding. > In such cases the input will be invariably of the same size as the modulus > and there is no room for padding anyway. > > (NB: in the code proper, you do use "nopadding" and not "unpadded" > which is better -- but also see below) Note, will use nopadding consistently in the next patch. > That said, I still fail to warm up to the idea of adding a parameter to > management-external-key. First, even with this precaution, signing can > fail in two cases: > > (i) the config file has "--management-external-key nopadding" but the > client version is <= 2. In such cases no warning will be printed but > management will get prepadded data with no ALG indicator which the > external signer will definitely fail to treat as PKCS1. Either signing will fail > (not sure how an existing client would handle that) or connection > will restart with verification error. I can add an extra warning to print if the client will not announce a new version. But I think that config will not really happen (the tightly coupled argument) > > So, in short, I suggest to just leave the management-external-key option alone > and only add a new parameter to PK_SIGN (more on that below) and make sure > the external sign dispatcher does not error out when padding is not PKCS1 > (ie. support at least RSA_PADDING_NONE and RSA_PADDING_PKCS1 in > rsa_priv_enc() for now) > > The early erroring out is only marginally useful as it does not catch > all cases as argued above. Also a user may try to deal with the error by setting > tls version max to 1.2 but that will also fail when openssl 1.1.1 is use -- this > time without triggering the early error-out. So we gain little by > mutilating this > option and all the complications it brings. > > The patch will be considerably simple once this change is taken out. I get what you saying here but that breaks compability with management clients that are on the old pkcs1/mangement interface. > In any case, both here (if we retain this) and in PK_SIGN a more generic > signalling is required. Else we wont be able to support external PSS > padding later -- just padding = PSS is not enough to do that, the hash > algorithm is > also required. The same is true for PKCS1 too but currently we do not support > external signer to add digest info for PKCS1 signatures. But going forward, > some external signers would need that option. > > I would suggest: PKS_SIGN <base64data>,ALG > where > ALG = RSA_NONE_PKCS1 (current default), > RSA_RAW (or RSA_NONE_NOPADDING) > RSA_<hash-alg>_PKCS1 > ECDSA (current default if key is EC) > with ALG missing to be interpreted as current defaults (PKCS1 > with digest info already prepended for RSA and ECDSA for EC). > My patch adds exactly that but with slightly different names for the algorithms. >> >> Using the management api client version instead might seem like the >> more logical way but since we only now that version very late, >> it would extra logic and complexity to deal with this asynchronous >> behaviour. Instead just give an error early if OpenSSL 1.1.1 and >> management-external-key without nopadding is detected. >> >> The interface is prepared for signalling PCKS1 and RSA-PSS support >> instead of signalling unpadded support. > > "instead of" --> "in addition to" ? > unpadded support --> "signature algorithm to use" > >> >> >> Patch v3: fix overlong lines and few other style patches. Note >> two overlong lines concerning mbedtls are not fixed as they >> are removed/shortend by the mbed tls patch to avoid conflicts >> >> Patch v4: Setting minimum TLS version proved to be not enough and >> instead of implementing a whole compability layer we require >> mangement-clients to implement the new feature when they want >> to use OpenSSL 1.1.1 >> >> Add a padding=ALGORITHM argument to pk-sig to indicate the >> algorithm. Drop adding PKCS1 ourselves. > > The code below adds ",ALG" to PK_SIGN, not padding=ALG to pk-sig. > Better make the above consistent with that. Yeah, the commit message is wrong. Noted. >> . >> @@ -833,6 +834,12 @@ END >> Base 64 encoded output of RSA_private_encrypt for RSA or ECDSA_sign() >> for EC using OpenSSL or mbedtls_pk_sign() using mbed TLS will provide a >> correct signature. >> +The rsa-sig interfaces expects PKCS1 padded signatures for RSA keys >> +(RSA_PKCS1_PADDING). EC signatures are always unpadded. >> >> + >> +The padding field is only present when pk-sig is used and >> +currently the following values can be requested PCKS1 and NOPADDING for RSA >> +certificates and NOPADDING for EC certificates. > > This is totally confusing. There is no reason to distinguish between > rsa-sig and pk-sig as used by the client although we should encourage all new > clients to use pk-sig only. These added lines may be replaced by: That comes from the inflexibility of our management code. I only accepts pk-sig when quering PKSIG and only accepts rsa-sig when querying RSSIG. > "For RSA keys, if signature algorithm is "RSA_NONE_PKCS1" or > unspecified, the data to sign contains the hash with digest info > header added. If > the algorithm is RSA_RAW, a raw RSA sign operation should be performed. Base 64 > encoded output of OpenSSL function RSA_private_encrypt() with > padding=RSA_PADDING_PKCS1 for the first case and > padding=RSA_PADDING_NONE in the second case creates the correct signature. > In case of EC keys Base 64 encoded output of ECDSA_sign() provides the correct > signature." > > And remove those references to ECDSA_sign() and RSA_private_encrypt() earlier. >> This capability is intended to allow the use of arbitrary cryptographic >> service providers with OpenVPN via the management interface. >> @@ -840,6 +847,10 @@ service providers with OpenVPN via the management interface. >> New and updated clients are expected to use the version command to announce >> a version > 1 and handle '>PK_SIGN' prompt and respond with 'pk-sig'. >> >> +The older rsa-sig and pk-sig interfaces hav no capability to indidicate the >> +requested padding algorithm. When the 'nopadding' using version >= 2 is required. >> +To support TLS 1.3 with OpenSSL 1.1.1 supporting unpadded signatures is required. >> + > > > Again, confusing. If you want to reiterate this what about: > "The signature algorithm is indicated in the PK_SIGN request only if the > or management client-version is > 2. In particular, to support TLS1.3 and > TLS1.2 using OpenSSL 1.1.1, non-pkcs1 padded signature support is required > and this can be indicated in the signing request only if the client > version is > 2." Yes, your wording is better. >> char * >> /* returns allocated base64 signature */ >> -management_query_pk_sig(struct management *man, >> - const char *b64_data) >> +management_query_pk_sig(struct management *man, const char *b64_data, >> + const char *padding) > > > Suggest to change padding -> sign_alg Okay. >> >> { >> const char *prompt = "PK_SIGN"; >> const char *desc = "pk-sign"; >> + struct buffer buf_data = alloc_buf(strlen(b64_data) + strlen(padding) + 20); >> + >> if (man->connection.client_version <= 1) >> { >> prompt = "RSA_SIGN"; >> desc = "rsa-sign"; >> } >> - return management_query_multiline_flatten(man, b64_data, prompt, desc, >> + >> + buf_write(&buf_data, b64_data, (int) strlen(b64_data)); >> + if (man->connection.client_version > 2) >> >> + { >> + buf_write(&buf_data, ",", (int) strlen(",")); >> + buf_write(&buf_data, padding, (int) strlen(padding)); >> + } >> + char* ret = management_query_multiline_flatten(man, >> + (char *)buf_bptr(&buf_data), prompt, desc, >> &man->connection.ext_key_state, &man->connection.ext_key_input); >> + free_buf(&buf_data); >> + return ret; >> } >> >> char * >> diff --git a/src/openvpn/manage.h b/src/openvpn/manage.h >> index d24abe09..4bfcfdbe 100644 >> --- a/src/openvpn/manage.h >> +++ b/src/openvpn/manage.h >> @@ -31,7 +31,7 @@ >> #include "socket.h" >> #include "mroute.h" >> >> -#define MANAGEMENT_VERSION 2 >> +#define MANAGEMENT_VERSION 3 >> #define MANAGEMENT_N_PASSWORD_RETRIES 3 >> #define MANAGEMENT_LOG_HISTORY_INITIAL_SIZE 100 >> #define MANAGEMENT_ECHO_BUFFER_SIZE 100 >> @@ -341,12 +341,18 @@ struct management *management_init(void); >> #ifdef MANAGEMENT_PF >> #define MF_CLIENT_PF (1<<7) >> #endif >> -#define MF_UNIX_SOCK (1<<8) >> -#define MF_EXTERNAL_KEY (1<<9) >> -#define MF_UP_DOWN (1<<10) >> -#define MF_QUERY_REMOTE (1<<11) >> -#define MF_QUERY_PROXY (1<<12) >> -#define MF_EXTERNAL_CERT (1<<13) >> +#define MF_UNIX_SOCK (1<<8) >> +#define MF_EXTERNAL_KEY (1<<9) >> +#define MF_EXTERNAL_KEY_NOPADDING (1<<10) >> +#define MF_EXTERNAL_KEY_PKCS1PAD (1<<11) >> +#define MF_UP_DOWN (1<<12) >> +#define MF_QUERY_REMOTE (1<<13) >> +#define MF_QUERY_PROXY (1<<14) >> +#define MF_EXTERNAL_CERT (1<<15) >> + >> +#define MF_RSA_PKCS1_PADDING 1 >> +#define MF_RSA_NO_PADDING 2 >> + > > > These extra defines and associated code can go if --management-external-key > is not changed. > >> >> >> bool management_open(struct management *man, >> const char *addr, >> @@ -430,7 +436,8 @@ void management_learn_addr(struct management *management, >> >> #endif >> >> -char *management_query_pk_sig(struct management *man, const char *b64_data); >> +char *management_query_pk_sig(struct management *man, const char *b64_data, >> + const char* pading); > > > pading -> padding for consistency.. > But padding -> sign_alg is my preference. > >> >> >> char *management_query_cert(struct management *man, const char *cert_name); >> >> diff --git a/src/openvpn/options.c b/src/openvpn/options.c >> index 406669a3..2291dd9d 100644 >> --- a/src/openvpn/options.c >> +++ b/src/openvpn/options.c >> @@ -2141,6 +2141,23 @@ options_postprocess_verify_ce(const struct options *options, const struct connec >> >> #endif >> >> +#if defined(ENABLE_CRYPTOAPI) >> + if (o->cryptoapi_cert && (tls_version_max() >= TLS_VER_1_3)) >> + { >> + msg(M_ERR, "Cryptoapi support currently is incompatible " >> + "with OpenSSL 1.1.1/TLS 1.3"); >> + } > > > TLS1.2 is also affected but for now ok like this. > I have a fix to support PSS in cryptoapi, just have to find some time to test it > thoroughly. Sigh.. I added these few lines as they quick to remove and point an error in configuration at the moment. And what tls_version() does NOT report the version that is currently enabled but the maximum TLS version that the SSL library supports. So it will always error out on OpenSSL 1.1.1 and crypto api use. > >> +#endif >> +#if defined(ENABLE_MANAGEMENT) >> + if ((tls_version_max() >= TLS_VER_1_3) && >> >> + (options->management_flags & MF_EXTERNAL_KEY) && >> + !(options->management_flags & (MF_EXTERNAL_KEY_NOPADDING)) >> >> + ) >> + { >> + msg(M_ERR, "management-external-key with OpenSSL 1.1.1 requires " >> + "the nopadding argument/support"); >> + } > > > Same as above but I think this check is not that useful.. The check can be translated as "If you use management-external-key with OpenSSL 1.1.1 you need to support the new API" I removed the rest of comment as I agree with them. But in summary. My patch basically amounts to: Support old style management-external-key with <= OpenSSL 1.1.0 and use and require a new API if we have OpenSSL 1.1.1 and to really move and have external key have a sane API, we would drop rsa-sig and support for older clients, even with <= OpenSSL 1.1.0 as you oppose my proposl for signalling that a new API should be used. (version in managemnet protocol is too late and not feasible in my opinion) Supporting a half working RSA_SIG option that breaks left and right is not desirable in my opinion. I would be really happy to drop the old support if no one objects. Arne
Somehow this didn't get copied to the list ---------- Forwarded message --------- From: Selva Nair <selva.nair@gmail.com> Date: Wed, Nov 14, 2018 at 11:06 AM Subject: Re: [Openvpn-devel] [PATCH v5 2/2] Add support for OpenSSL TLS 1.3 when using management-external-key To: Arne Schwabe <arne@rfc2549.org> Hi, On Wed, Nov 14, 2018 at 10:56 AM Arne Schwabe <arne@rfc2549.org> wrote: > > Am 14.11.18 um 16:18 schrieb Selva Nair: > > Hi, > > > > snipping a lot of useful stuff as we tend agree on those.. > > .. > > > >> But in summary. > >> > >> My patch basically amounts to: Support old style management-external-key > >> with <= OpenSSL 1.1.0 and use and require a new API if we have OpenSSL > >> 1.1.1 and to really move and have external key have a sane API, we would > >> drop rsa-sig and support for older clients, even with <= OpenSSL 1.1.0 > >> as you oppose my proposl for signalling that a new API should be used. > >> (version in managemnet protocol is too late and not feasible in my opinion) > >> Supporting a half working RSA_SIG option that breaks left and right is > >> not desirable in my opinion. > > > > My point is that even with "--management-external-key foo bar", we > > will be sending > > a non workable signature request to old clients so changing that > > option is not really > > useful. In other words the early erroring out works only half the time > > and all that code > > complication is not worth it. > > Okay, I think you misunderstood my code. What it does is basically if we > detect having TLS 1.3 support (max_tls_version >= TLS 1.3) and not a > nopadding argument we error out, saying that this combination cannot work. > > Yes that means that if you upgrade to OpenSSL 1.1.1 you need to support > the new API but I think that is acceptable. > > Unless I overlooked something, I don't see any situation in which we ask > for an unsupported signature. Consider this: (i) config has --management-external-key nopadding but client announces version 2. We will not error out but send the signature request as PK_SIGN <base64data> without the ALG as client version is not 3 and fail (ii) tls version max is set 1.2 and openssl 1.1.1 is in use both on server and client. PSS signing will get negotiated but we will not error out early as TLS 1.3 is not in use. That's why I say that this extension of management-external-key is not worth it. Am I missing something? Selva
Hi, A thought: why not split this patch into two: (i) extend PK_SIGN to optionally signal ALG (signalled only if client_version > 2). Include all the changes to rsa_priv_enc() etc to to handle PSS sign requests from OpenSSL 1.1.1. If client version is <= 2 continue to use PK_SIGN as before provided the signature required is PKCS1 for RSA or ECDSA. Else error out manage.c. This ensures backward compat to the extent possible. (ii) Amend management-external-key to take an additional option and do whatever one can do with it for an early error report. Anyway, my suggestion is not even bother with (ii) but this way we can quickly get (i) finalized. Unless you already decided to drop (ii) :) Only downside (or upside depending on your pov) to this is once (i) is merged in we will start including ALG in PK_SIGN for new clients (version 3+) so if merging (ii), that should happen before a subsequent release. Selva <div dir="ltr"><div><div><div><div><div>Hi,<br><br>A thought: why not split this patch into two:<br></div><br></div>(i) extend PK_SIGN to optionally signal ALG (signalled only if <br>client_version > 2). Include all the changes to rsa_priv_enc()<br>etc to to handle PSS sign requests from OpenSSL 1.1.1.<br></div></div><br></div><div>If client version is <= 2 continue to use PK_SIGN as before<br>provided the signature required is PKCS1 for RSA or ECDSA.<br></div><div>Else error out manage.c.<br><br></div><div>This ensures backward compat to the extent possible.<br></div><div><br></div>(ii) Amend management-external-key to take an additional option<br>and do whatever one can do with it for an early error report.<br><div><div><div><div><div><div><br></div><div>Anyway, my suggestion is not even bother with (ii) but this way we<br>can quickly get (i) finalized.<br><br></div><div>Unless you already decided to drop (ii) :)<br><br></div><div>Only downside (or upside depending on your pov) to this is<br>once (i) is merged in we will start including ALG in PK_SIGN<br></div><div>for new clients (version 3+) so if merging (ii), that should happen<br></div><div>before a subsequent release.<br></div><div> <br></div><div>Selva</div></div></div></div></div></div></div>
>> Unless I overlooked something, I don't see any situation in which we ask >> for an unsupported signature. > > Consider this: > (i) config has --management-external-key nopadding but client announces version > 2. We will not error out but send the signature request as > PK_SIGN <base64data> > without the ALG as client version is not 3 and fail We can error out on version on the management line. But this is also a kind of obscure misconfiguration since why would add nopadding to the config if you cannot support it? > (ii) tls version max is set 1.2 and openssl 1.1.1 is in use both on > server and client. > PSS signing will get negotiated but we will not error out early as TLS > 1.3 is not in use. > > That's why I say that this extension of management-external-key is not worth it. > > Am I missing something? > tls_version_max will still report TLS 1.3 as it not affected by the version set in config but really the max the library is capable of irrespectable tls min/max version. Arne
On Thu, Nov 15, 2018 at 2:22 AM Arne Schwabe <arne@rfc2549.org> wrote: > > >> Unless I overlooked something, I don't see any situation in which we ask > >> for an unsupported signature. > > > > Consider this: > > (i) config has --management-external-key nopadding but client announces > version > > 2. We will not error out but send the signature request as > > PK_SIGN <base64data> > > without the ALG as client version is not 3 and fail > > We can error out on version on the management line. But this is also a > kind of obscure misconfiguration since why would add nopadding to the > config if you cannot support it? > True, but by same argument then we need not worry about backward compatibility of management protocol at all, do we? We could say, why would any one use openvpn.exe that speaks MI version 3 with a client that cannot support it. Anyway, for backward compat its enough to check client version and then either error out if ALG is not PKCS1 or ECDSA or add ALG to PK_SIGN. I fail to appreciate the utility of early erroring out feature -- it was meaningful in v1 where you had tried to downgrade to TLS 1.2 to plough along without causing an error. But that turned out to be not enough. > > (ii) tls version max is set 1.2 and openssl 1.1.1 is in use both on > > server and client. > > PSS signing will get negotiated but we will not error out early as TLS > > 1.3 is not in use. > > > > That's why I say that this extension of management-external-key is not > worth it. > > > > Am I missing something? > > > > tls_version_max will still report TLS 1.3 as it not affected by the > version set in config but really the max the library is capable of > irrespectable tls min/max version. > Aha, I missed that. Still I really do not understand the need for erroring here instead of when prompting for PK_SIGN based on client version. Much simpler. Selva <div dir="ltr"><br><br><div class="gmail_quote"><div dir="ltr">On Thu, Nov 15, 2018 at 2:22 AM Arne Schwabe <<a href="mailto:arne@rfc2549.org">arne@rfc2549.org</a>> wrote:<br></div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><br> >> Unless I overlooked something, I don't see any situation in which we ask<br> >> for an unsupported signature.<br> > <br> > Consider this:<br> > (i) config has --management-external-key nopadding but client announces version<br> > 2. We will not error out but send the signature request as<br> > PK_SIGN <base64data><br> > without the ALG as client version is not 3 and fail<br> <br> We can error out on version on the management line. But this is also a<br> kind of obscure misconfiguration since why would add nopadding to the<br> config if you cannot support it?<br></blockquote><div><br></div><div>True, but by same argument then we need not worry about backward compatibility</div><div>of management protocol at all, do we? We could say, why would any one use</div><div>openvpn.exe that speaks MI version 3 with a client that cannot support it.</div><div><br></div><div>Anyway, for backward compat its enough to check client version and then</div><div>either error out if ALG is not PKCS1 or ECDSA or add ALG to PK_SIGN.</div><div><br></div><div>I fail to appreciate the utility of early erroring out feature -- it was meaningful</div><div>in v1 where you had tried to downgrade to TLS 1.2 to plough along without</div><div>causing an error. But that turned out to be not enough.</div><div> <br></div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"> > (ii) tls version max is set 1.2 and openssl 1.1.1 is in use both on<br> > server and client.<br> > PSS signing will get negotiated but we will not error out early as TLS<br> > 1.3 is not in use.<br> > <br> > That's why I say that this extension of management-external-key is not worth it.<br> > <br> > Am I missing something?<br> > <br> <br> tls_version_max will still report TLS 1.3 as it not affected by the<br> version set in config but really the max the library is capable of<br> irrespectable tls min/max version.<br></blockquote><div><br></div><div>Aha, I missed that. Still I really do not understand the need for erroring here</div><div>instead of when prompting for PK_SIGN based on client version.</div><div>Much simpler.</div><div><br></div><div>Selva</div></div></div>
> > > > (ii) tls version max is set 1.2 and openssl 1.1.1 is in use both on > > server and client. > > PSS signing will get negotiated but we will not error out early as TLS > > 1.3 is not in use. > > > > That's why I say that this extension of management-external-key is > not worth it. > > > > Am I missing something? > > > > tls_version_max will still report TLS 1.3 as it not affected by the > version set in config but really the max the library is capable of > irrespectable tls min/max version. > > > Aha, I missed that. Still I really do not understand the need for > erroring here > instead of when prompting for PK_SIGN based on client version. > Much simpler. It did this because my initial OpenSSL 1.1.1 client did not have any problem, only after I upgraded the server to 1.1.1. I want to avoid the situation that OpenSSL 1.1.1 is used and then just "breaks for no reason" and erroring out early and tell the "This will not really work" is a better approach. Arne
Hi, Reviving this thread/patch as now users are running into this padding issue (trac 1216 <https://community.openvpn.net/openvpn/ticket/1216>). IIRC, we more-or-less agreed upon adding an argument (nopadding, pss etc..) to >PK_SIGN for new clients and erroring out with old clients that cannot sign with PSS padding. Selva <div dir="ltr"><div dir="ltr">Hi,<br><br>Reviving this thread/patch as now users are running into this padding issue (<a href="https://community.openvpn.net/openvpn/ticket/1216">trac 1216</a>).<br><br><div>IIRC, we more-or-less agreed upon adding an argument (nopadding, pss etc..)</div><div>to >PK_SIGN for new clients and erroring out with old clients that</div><div>cannot sign with PSS padding.</div><div><br></div><div>Selva<br></div></div><br></div>
Am 20.09.19 um 22:55 schrieb Selva Nair: > Hi, > > Reviving this thread/patch as now users are running into this padding > issue (trac 1216 <https://community.openvpn.net/openvpn/ticket/1216>). > > IIRC, we more-or-less agreed upon adding an argument (nopadding, pss etc..) > to >PK_SIGN for new clients and erroring out with old clients that > cannot sign with PSS padding. > > Selva > Yeah. We did not really to a conclusion if we wanted backwards compatibility or not. Since it seems that OpenSSL 1.1.1 requires the management-client to understand the new way of signatures anyway, I would say we require the management client to be able to understand the signature in any case. I think the missing bit of piece for the patch is if we want to error out early if we detect a config that *might* not work (the nopadding argument or any other argument to the management-external-key) or if we do not error at this point and fail then when we actually require PSS signature. I am more for the first version because otherwise you end up with configurations that work fine until the server is upgraded to OpenSSL 1.1.1 and then the client stops working without anything being change (yes I realise that is already the case at the moment) Arne
Forgot copy this to the list -- sending again On Mon, Sep 23, 2019 at 6:19 AM Arne Schwabe <arne@rfc2549.org> wrote: > > Am 20.09.19 um 22:55 schrieb Selva Nair: > > Hi, > > > > Reviving this thread/patch as now users are running into this padding > > issue (trac 1216 <https://community.openvpn.net/openvpn/ticket/1216>). > > > > IIRC, we more-or-less agreed upon adding an argument (nopadding, pss etc..) > > to >PK_SIGN for new clients and erroring out with old clients that > > cannot sign with PSS padding. > > > > Selva > > > Yeah. > > We did not really to a conclusion if we wanted backwards compatibility > or not. Since it seems that OpenSSL 1.1.1 requires the management-client > to understand the new way of signatures anyway, I would say we require > the management client to be able to understand the signature in any case. > > I think the missing bit of piece for the patch is if we want to error > out early if we detect a config that *might* not work (the nopadding > argument or any other argument to the management-external-key) or if we > do not error at this point and fail then when we actually require PSS > signature. I am more for the first version because otherwise you end up > with configurations that work fine until the server is upgraded to > OpenSSL 1.1.1 and then the client stops working without anything being > change (yes I realise that is already the case at the moment) Well, I can live with that --- at least we'll be able to tell the users to update their client to get the signature request, which is not the case now. Selva
diff --git a/doc/management-notes.txt b/doc/management-notes.txt index 17645c1d..f685af28 100644 --- a/doc/management-notes.txt +++ b/doc/management-notes.txt @@ -816,6 +816,7 @@ actual private key. When the SSL protocol needs to perform a sign operation, the data to be signed will be sent to the management interface via a notification as follows: +>PK_SIGN:[BASE64_DATA],[ALG] (if client announces support for management version > 2) >PK_SIGN:[BASE64_DATA] (if client announces support for management version > 1) >RSA_SIGN:[BASE64_DATA] (only older clients will be prompted like this) @@ -823,7 +824,7 @@ The management interface client should then create an appropriate signature of the (decoded) BASE64_DATA using the private key and return the SSL signature as follows: -pk-sig (or rsa-sig) +pk-sig (or rsa-sig) [BASE64_SIG_LINE] . . @@ -833,6 +834,12 @@ END Base 64 encoded output of RSA_private_encrypt for RSA or ECDSA_sign() for EC using OpenSSL or mbedtls_pk_sign() using mbed TLS will provide a correct signature. +The rsa-sig interfaces expects PKCS1 padded signatures for RSA keys +(RSA_PKCS1_PADDING). EC signatures are always unpadded. + +The padding field is only present when pk-sig is used and +currently the following values can be requested PCKS1 and NOPADDING for RSA +certificates and NOPADDING for EC certificates. This capability is intended to allow the use of arbitrary cryptographic service providers with OpenVPN via the management interface. @@ -840,6 +847,10 @@ service providers with OpenVPN via the management interface. New and updated clients are expected to use the version command to announce a version > 1 and handle '>PK_SIGN' prompt and respond with 'pk-sig'. +The older rsa-sig and pk-sig interfaces hav no capability to indidicate the +requested padding algorithm. When the 'nopadding' using version >= 2 is required. +To support TLS 1.3 with OpenSSL 1.1.1 supporting unpadded signatures is required. + COMMAND -- certificate (OpenVPN 2.4 or higher) ---------------------------------------------- Provides support for external storage of the certificate. Requires the diff --git a/doc/openvpn.8 b/doc/openvpn.8 index e80d4696..3cd5d944 100644 --- a/doc/openvpn.8 +++ b/doc/openvpn.8 @@ -2739,10 +2739,13 @@ Allow management interface to override directives (client\-only). .\"********************************************************* .TP -.B \-\-management\-external\-key +.B \-\-management\-external\-key [nopadding] [pkcs1] Allows usage for external private key file instead of .B \-\-key -option (client\-only). +option (client\-only). The optional parameters nopadding and +pkcs1 signal support for different padding algorithms. See +doc/mangement-notes.txt for a complete description of this +feature. .\"********************************************************* .TP .B \-\-management\-external\-cert certificate\-hint diff --git a/src/openvpn/manage.c b/src/openvpn/manage.c index 8b633f20..62d4bc7b 100644 --- a/src/openvpn/manage.c +++ b/src/openvpn/manage.c @@ -3639,18 +3639,30 @@ management_query_multiline_flatten(struct management *man, char * /* returns allocated base64 signature */ -management_query_pk_sig(struct management *man, - const char *b64_data) +management_query_pk_sig(struct management *man, const char *b64_data, + const char *padding) { const char *prompt = "PK_SIGN"; const char *desc = "pk-sign"; + struct buffer buf_data = alloc_buf(strlen(b64_data) + strlen(padding) + 20); + if (man->connection.client_version <= 1) { prompt = "RSA_SIGN"; desc = "rsa-sign"; } - return management_query_multiline_flatten(man, b64_data, prompt, desc, + + buf_write(&buf_data, b64_data, (int) strlen(b64_data)); + if (man->connection.client_version > 2) + { + buf_write(&buf_data, ",", (int) strlen(",")); + buf_write(&buf_data, padding, (int) strlen(padding)); + } + char* ret = management_query_multiline_flatten(man, + (char *)buf_bptr(&buf_data), prompt, desc, &man->connection.ext_key_state, &man->connection.ext_key_input); + free_buf(&buf_data); + return ret; } char * diff --git a/src/openvpn/manage.h b/src/openvpn/manage.h index d24abe09..4bfcfdbe 100644 --- a/src/openvpn/manage.h +++ b/src/openvpn/manage.h @@ -31,7 +31,7 @@ #include "socket.h" #include "mroute.h" -#define MANAGEMENT_VERSION 2 +#define MANAGEMENT_VERSION 3 #define MANAGEMENT_N_PASSWORD_RETRIES 3 #define MANAGEMENT_LOG_HISTORY_INITIAL_SIZE 100 #define MANAGEMENT_ECHO_BUFFER_SIZE 100 @@ -341,12 +341,18 @@ struct management *management_init(void); #ifdef MANAGEMENT_PF #define MF_CLIENT_PF (1<<7) #endif -#define MF_UNIX_SOCK (1<<8) -#define MF_EXTERNAL_KEY (1<<9) -#define MF_UP_DOWN (1<<10) -#define MF_QUERY_REMOTE (1<<11) -#define MF_QUERY_PROXY (1<<12) -#define MF_EXTERNAL_CERT (1<<13) +#define MF_UNIX_SOCK (1<<8) +#define MF_EXTERNAL_KEY (1<<9) +#define MF_EXTERNAL_KEY_NOPADDING (1<<10) +#define MF_EXTERNAL_KEY_PKCS1PAD (1<<11) +#define MF_UP_DOWN (1<<12) +#define MF_QUERY_REMOTE (1<<13) +#define MF_QUERY_PROXY (1<<14) +#define MF_EXTERNAL_CERT (1<<15) + +#define MF_RSA_PKCS1_PADDING 1 +#define MF_RSA_NO_PADDING 2 + bool management_open(struct management *man, const char *addr, @@ -430,7 +436,8 @@ void management_learn_addr(struct management *management, #endif -char *management_query_pk_sig(struct management *man, const char *b64_data); +char *management_query_pk_sig(struct management *man, const char *b64_data, + const char* pading); char *management_query_cert(struct management *man, const char *cert_name); diff --git a/src/openvpn/options.c b/src/openvpn/options.c index 406669a3..2291dd9d 100644 --- a/src/openvpn/options.c +++ b/src/openvpn/options.c @@ -2141,6 +2141,23 @@ options_postprocess_verify_ce(const struct options *options, const struct connec #endif +#if defined(ENABLE_CRYPTOAPI) + if (o->cryptoapi_cert && (tls_version_max() >= TLS_VER_1_3)) + { + msg(M_ERR, "Cryptoapi support currently is incompatible " + "with OpenSSL 1.1.1/TLS 1.3"); + } +#endif +#if defined(ENABLE_MANAGEMENT) + if ((tls_version_max() >= TLS_VER_1_3) && + (options->management_flags & MF_EXTERNAL_KEY) && + !(options->management_flags & (MF_EXTERNAL_KEY_NOPADDING)) + ) + { + msg(M_ERR, "management-external-key with OpenSSL 1.1.1 requires " + "the nopadding argument/support"); + } +#endif /* * Windows-specific options. */ @@ -5151,9 +5168,33 @@ add_option(struct options *options, options->management_write_peer_info_file = p[1]; } #ifdef ENABLE_MANAGEMENT - else if (streq(p[0], "management-external-key") && !p[1]) + else if (streq(p[0], "management-external-key")) { VERIFY_PERMISSION(OPT_P_GENERAL); + for (int j = 1; j < MAX_PARMS && p[j] != NULL; ++j) + { + if (streq(p[j], "nopadding")) + { + options->management_flags |= MF_EXTERNAL_KEY_NOPADDING; + } + else if (p[1] && streq(p[1], "pkcs1")) + { + options->management_flags |= MF_EXTERNAL_KEY_PKCS1PAD; + } + else + { + msg(msglevel, "Unknown management-external-key flag: %s" , p[j]); + } + } + /* + * When no option is present, assume that only PKCS1 + * padding is supported + */ + if (! (options->management_flags & + (MF_EXTERNAL_KEY_NOPADDING | MF_EXTERNAL_KEY_PKCS1PAD))) + { + options->management_flags |= MF_EXTERNAL_KEY_PKCS1PAD; + } options->management_flags |= MF_EXTERNAL_KEY; } else if (streq(p[0], "management-external-cert") && p[1] && !p[2]) @@ -8456,4 +8497,4 @@ add_option(struct options *options, } err: gc_free(&gc); -} \ No newline at end of file +} diff --git a/src/openvpn/ssl_mbedtls.c b/src/openvpn/ssl_mbedtls.c index f7e8c2d0..09b1a8fa 100644 --- a/src/openvpn/ssl_mbedtls.c +++ b/src/openvpn/ssl_mbedtls.c @@ -626,7 +626,6 @@ tls_ctx_use_external_signing_func(struct tls_root_ctx *ctx, } #ifdef ENABLE_MANAGEMENT - /** Query the management interface for a signature, see external_sign_func. */ static bool management_sign_func(void *sign_ctx, const void *src, size_t src_len, @@ -641,7 +640,11 @@ management_sign_func(void *sign_ctx, const void *src, size_t src_len, goto cleanup; } - if (!(dst_b64 = management_query_pk_sig(management, src_b64))) + /* + * We only use PKCS1 signatures at the moment in mbed TLS, + * there the signature parameter is hardcoded + */ + if (!(dst_b64 = management_query_pk_sig(management, src_b64, "PKCS1"))) { goto cleanup; } diff --git a/src/openvpn/ssl_openssl.c b/src/openvpn/ssl_openssl.c index c2c8fdc0..237c2b55 100644 --- a/src/openvpn/ssl_openssl.c +++ b/src/openvpn/ssl_openssl.c @@ -1079,24 +1079,46 @@ openvpn_extkey_rsa_finish(RSA *rsa) return 1; } -/* Pass the input hash in 'dgst' to management and get the signature back. +/* + * Convert OpenSSL's constant to the strings used in the management + * interface query + */ +const char* +get_sig_padding_name(const int padding) +{ + switch(padding) + { + case RSA_PKCS1_PADDING: + return "PKCS1"; + case RSA_NO_PADDING: + return "NOPADDING"; + default: + return "UNKNOWN"; + } +} + +/* + * Pass the input hash in 'dgst' to management and get the signature back. * On input siglen contains the capacity of the buffer 'sig'. * On return signature is in sig. + * pkcs1 controls if pkcs1 padding is required * Return value is signature length or -1 on error. */ static int get_sig_from_man(const unsigned char *dgst, unsigned int dgstlen, - unsigned char *sig, unsigned int siglen) + unsigned char *sig, unsigned int siglen, + int padding) { char *in_b64 = NULL; char *out_b64 = NULL; int len = -1; - /* convert 'dgst' to base64 */ - if (management - && openvpn_base64_encode(dgst, dgstlen, &in_b64) > 0) + int bencret = openvpn_base64_encode(dgst, dgstlen, &in_b64); + + if (management && bencret > 0) { - out_b64 = management_query_pk_sig(management, in_b64); + out_b64 = management_query_pk_sig(management, in_b64, + get_sig_padding_name(padding)); } if (out_b64) { @@ -1110,18 +1132,19 @@ get_sig_from_man(const unsigned char *dgst, unsigned int dgstlen, /* sign arbitrary data */ static int -rsa_priv_enc(int flen, const unsigned char *from, unsigned char *to, RSA *rsa, int padding) +rsa_priv_enc(int flen, const unsigned char *from, unsigned char *to, RSA *rsa, + int padding) { unsigned int len = RSA_size(rsa); int ret = -1; - if (padding != RSA_PKCS1_PADDING) + if (padding != RSA_PKCS1_PADDING && padding != RSA_NO_PADDING) { RSAerr(RSA_F_RSA_OSSL_PRIVATE_ENCRYPT, RSA_R_UNKNOWN_PADDING_TYPE); return -1; } - ret = get_sig_from_man(from, flen, to, len); + ret = get_sig_from_man(from, flen, to, len, padding); return (ret == len)? ret : -1; } @@ -1215,7 +1238,13 @@ ecdsa_sign(int type, const unsigned char *dgst, int dgstlen, unsigned char *sig, unsigned int *siglen, const BIGNUM *kinv, const BIGNUM *r, EC_KEY *ec) { int capacity = ECDSA_size(ec); - int len = get_sig_from_man(dgst, dgstlen, sig, capacity); + /* + * ECDSA does not seem to have proper constants for paddings since + * there are only signatures without padding at the moment, reuse + * RSA_NO_PADDING for now as it will trigger querying for "NOPADDING" in the + * management interface + */ + int len = get_sig_from_man(dgst, dgstlen, sig, capacity, RSA_NO_PADDING); if (len > 0) {
For TLS 1.0 to 1.2 and OpenSSL 1.1.0 calls us and requires a PKCS1 padded response. As TLS 1.3 mandates RSA-PSS padding support and also requires an TLS 1.3 implementation to support RSA-PSS for older TLS version, OpenSSL will query us to sign an already RSA-PSS padded string. This patch adds an 'unpadded' and 'pkcs1' parameter to the management-external-key option to signal that the client is able to support pkcs1 as well as unpadded signature requests. Since clients that implement the management-external-key interface are usually rather tightly integrated solutions (OpenVPN Connect in the past, OpenVPN for Android), it is reasonable to expect that upgrading the OpenSSL library can be done together with management interface changes. Therefore we provide no backwards compatbility for mangement-interface clients not supporting OpenSSL 1.1.1. Using the management api client version instead might seem like the more logical way but since we only now that version very late, it would extra logic and complexity to deal with this asynchronous behaviour. Instead just give an error early if OpenSSL 1.1.1 and management-external-key without nopadding is detected. The interface is prepared for signalling PCKS1 and RSA-PSS support instead of signalling unpadded support. Patch v3: fix overlong lines and few other style patches. Note two overlong lines concerning mbedtls are not fixed as they are removed/shortend by the mbed tls patch to avoid conflicts Patch v4: Setting minimum TLS version proved to be not enough and instead of implementing a whole compability layer we require mangement-clients to implement the new feature when they want to use OpenSSL 1.1.1 Add a padding=ALGORITHM argument to pk-sig to indicate the algorithm. Drop adding PKCS1 ourselves. Patch v5: Send the right version of the patch Signed-off-by: Arne Schwabe <arne@rfc2549.org> --- doc/management-notes.txt | 13 ++++++++++- doc/openvpn.8 | 7 ++++-- src/openvpn/manage.c | 18 +++++++++++--- src/openvpn/manage.h | 23 +++++++++++------- src/openvpn/options.c | 45 +++++++++++++++++++++++++++++++++-- src/openvpn/ssl_mbedtls.c | 7 ++++-- src/openvpn/ssl_openssl.c | 49 +++++++++++++++++++++++++++++++-------- 7 files changed, 134 insertions(+), 28 deletions(-)