/** Generate a new session ticket * * Signs the administrator configured key, using the private key associated with the * SSL context, then hashes the signature to get a key of an appropriate length, * which is fed to the hmac and encryption contexts for the session ticket. * * @param out Where to write the derived session ticket key. * @param pkey used to the create the signature. * @param key to be signed using the private key, then hashed. * @param keylen length of key to be signed. * @return 0 on success, -1 on failure. */ static int tls_session_ticket_key(uint8_t out[SHA256_DIGEST_LENGTH], EVP_PKEY *pkey, uint8_t const *key, size_t keylen) { int ret; const EVP_MD *md = EVP_sha256(); EVP_MD_CTX mdctx; unsigned int outlen; uint8_t *sig; EVP_MD_CTX_init(&mdctx); ret = EVP_DigestInit(&mdctx, md); if (ret != 1) { ERROR("Failed initialising digest: %s", ERR_error_string(ERR_get_error(), NULL)); return -1; } ret = EVP_SignInit(&mdctx, md); if (ret != 1) { ERROR("Failed initialising signing context: %s", ERR_error_string(ERR_get_error(), NULL)); error: EVP_MD_CTX_cleanup(&mdctx); return -1; } ret = EVP_SignUpdate(&mdctx, key, keylen); if (ret != 1) { ERROR("Failed signing key: %s", ERR_error_string(ERR_get_error(), NULL)); goto error; } ret = EVP_SignFinal(&mdctx, NULL, &outlen, pkey); if (ret != 1) { ERROR("Failed finalising digest signature: %s", ERR_error_string(ERR_get_error(), NULL)); goto error; } MEM(sig = talloc_array(NULL, uint8_t, outlen)); ret = EVP_SignFinal(&mdctx, sig, &outlen, pkey); if (ret != 1) { ERROR("Failed finalising digest signature: %s", ERR_error_string(ERR_get_error(), NULL)); goto error; } EVP_MD_CTX_cleanup(&mdctx); EVP_MD_CTX_init(&mdctx); ret = EVP_DigestInit(&mdctx, md); if (ret != 1) { ERROR("Failed initialising digest: %s", ERR_error_string(ERR_get_error(), NULL)); talloc_free(sig); goto error; } ret = EVP_DigestUpdate(&mdctx, sig, outlen); if (ret != 1) { ERROR("Failed updating digest: %s", ERR_error_string(ERR_get_error(), NULL)); talloc_free(sig); goto error; } ret = EVP_DigestFinal(&mdctx, out, NULL); talloc_free(sig); if (ret != 1) { ERROR("Failed updating digest: %s", ERR_error_string(ERR_get_error(), NULL)); goto error; } return 0; } Anyone have opinions on this? The idea is to allow multiple RADIUS servers to calculate the same key independently without a common store, and to ensure that the derived keys are sufficiently complex, regardless of what the administrator configures. There's no standard for this that i've seen, nor is there a situation that I can see where deploying heterogeneous RADIUS servers in a HA cluster is useful. RFC5077 recommends periodic key rotations, which is possible, as 'key', is the result of a template expansion, which could be an xlat, attr ref or exec. I've confirmed that if an incorrect key is provided via the SSL_CTX_set_tlsext_ticket_key_cb that auth continues normally as if no ticket had been presented, and a new ticket is generated. -Arran Tue Mar 31 05:57:15 2015 : Debug: (5) eap_peap: New session ticket: 0x6e8b68c6803654c78bf7e6db15d7ea00 Tue Mar 31 05:57:15 2015 : Debug: (5) eap_peap: Session ticket key: 0x35 Tue Mar 31 05:57:15 2015 : Debug: (5) eap_peap: Session ticket key (derived): 0x11ab45219b8ebafac633475ac0a9be597055b26a27c4d196ff542fa6834a860b Tue Mar 31 05:57:15 2015 : Debug: (5) eap_peap: TLS_accept: SSLv3 write session ticket A Tue Mar 31 05:57:15 2015 : Debug: (13) eap_peap: Got session ticket: 0x6e8b68c6803654c78bf7e6db15d7ea00 Tue Mar 31 05:57:15 2015 : Debug: (13) eap_peap: Session ticket key: 0x3133 Tue Mar 31 05:57:15 2015 : Debug: (13) eap_peap: Session ticket key (derived): 0x9a12beeaf8d3a9ed30d50e065c21e2260a62f9bbabd16616873f3923cb8e90a1 Tue Mar 31 05:57:15 2015 : Debug: (16) eap_peap: New session ticket: 0x6928501f7ea2e7cfddc26da251f6d7f2 Tue Mar 31 05:57:15 2015 : Debug: (16) eap_peap: Session ticket key: 0x3136 Tue Mar 31 05:57:15 2015 : Debug: (16) eap_peap: Session ticket key (derived): 0x5979e02312c1b500bd32f3a5ad785c19e4a9f1d0ba4b4c8083b39252ea216ce9 Tue Mar 31 05:57:15 2015 : Debug: (16) eap_peap: TLS_accept: SSLv3 write session ticket A Tue Mar 31 05:57:15 2015 : Debug: (24) eap_peap: Got session ticket: 0x6928501f7ea2e7cfddc26da251f6d7f2 Tue Mar 31 05:57:15 2015 : Debug: (24) eap_peap: Session ticket key: 0x3234 Tue Mar 31 05:57:15 2015 : Debug: (24) eap_peap: Session ticket key (derived): 0x31e2bb458f5d9ef76d0a7d63696e3b33d1f57d1e4ef5a3f2f6d880d6135b8b4a Tue Mar 31 05:57:15 2015 : Debug: (27) eap_peap: New session ticket: 0x62a418806a4c58025628864c5b3a8af0 Tue Mar 31 05:57:15 2015 : Debug: (27) eap_peap: Session ticket key: 0x3237 Tue Mar 31 05:57:15 2015 : Debug: (27) eap_peap: Session ticket key (derived): 0x6c09a944a07cece8fef510427b41041d831f2dd8d8430e9be49e9bb1233ad32f Tue Mar 31 05:57:15 2015 : Debug: (27) eap_peap: TLS_accept: SSLv3 write session ticket A Arran Cudbard-Bell <a.cudbardb@freeradius.org> FreeRADIUS development team FD31 3077 42EC 7FCD 32FE 5EE2 56CF 27F9 30A8 CAA2
* * Signs the administrator configured key, using the private key associated with the * SSL context, then hashes the signature to get a key of an appropriate length, * which is fed to the hmac and encryption contexts for the session ticket. wait. What? I'm not parsing what you're trying to do there, and it's triggering my security spidy sense. Why do you ever want to hash a signature to get an encryption key? --Sam
On Mar 31, 2015, at 1:19 PM, Sam Hartman <hartmans@mit.edu> wrote:
wait. What? I'm not parsing what you're trying to do there, and it's triggering my security spidy sense. Why do you ever want to hash a signature to get an encryption key?
The problem is that the SSL session tickets are encrypted with a key known only to the server. This is a good idea, because it means that the client can't impersonate the server. However... if you have two servers, they must both know the key. They can communicate via a DB, which means the benefit of session tickets go away. Or, they can derive the key from some secret data known only to the servers. The method Arran came up with is to sign the various user-identifiying fields with the servers private key. Then hash that to get a key which is unique to the user, and known only to the server. If there's a simpler way to do this, I'd be happy to know it. Alan DeKok.
On 31 Mar 2015, at 13:19, Sam Hartman <hartmans@mit.edu> wrote:
* * Signs the administrator configured key, using the private key associated with the * SSL context, then hashes the signature to get a key of an appropriate length, * which is fed to the hmac and encryption contexts for the session ticket.
wait. What? I'm not parsing what you're trying to do there, and it's triggering my security spidy sense.
Requirements: - A cluster of servers need to derive the same session ticket key without communicating with each other. - The key should be derived from something the administrator configures, and the private key set for the SSL context. So if administrators choose simple keys, they don't open themselves up to session ticket spoofing. - The derived key must be a fixed length.
Why do you ever want to hash a signature to get an encryption key?
To get a fixed length key. Different certificate types will generate signatures of differing sizes. If there's a better way to generate a key of a fixed length, using an administrator provided key string, and a private key then i'd definitely be open to it. Using the private key to sign the administrator configured key was a trick from the original NGINX implementation of RFC 5077 session resumption. There they just took the first 48 bytes of the signature. Arran Cudbard-Bell <a.cudbardb@freeradius.org> FreeRADIUS development team FD31 3077 42EC 7FCD 32FE 5EE2 56CF 27F9 30A8 CAA2
"Arran" == Arran Cudbard-Bell <a.cudbardb@freeradius.org> writes:
>> On 31 Mar 2015, at 13:19, Sam Hartman <hartmans@mit.edu> wrote: >> >> * * Signs the administrator configured key, using the private key >> associated with the * SSL context, then hashes the signature to >> get a key of an appropriate length, * which is fed to the hmac >> and encryption contexts for the session ticket. >> >> >> wait. What? I'm not parsing what you're trying to do there, and >> it's triggering my security spidy sense. Arran> Requirements: Arran> - A cluster of servers need to derive the same session ticket Arran> key without communicating with each other. Arran> - The key should be derived from something the administrator Arran> configures, and the private key set for the SSL context. So Arran> if administrators choose simple keys, they don't open Arran> themselves up to session ticket spoofing. Arran> - The derived key must be a fixed length. OK. So, I'd handle this by providing a utility to generate a strong random key and copy that between servers. The disadvantage is that you don't leverage the private key. The advantage is that it's secure. Alan says something about a per-user ticket session key. You don't need that; you can have the same encryption key per-cluster, provided that you both encrypt and MAC and you don't do something horrible with how you encrypt things like reuse counters or nonces. You're assuming that if I sign the same data twice the signature will be the same. That's true for RSA with a particular old type of padding. That is not generally true of public key signatures. I can't remember off the top of my head if it is a desirable security property that signing the same item multiple times generates distinct signatures or not. Hashing the signature definitely makes it better. The enginex design really scares me. I don't know of a solution that meets your requirements as stated and that I know how to evaluate the security properties of. Besides what I mentioned above , you could take the private key itself plus the input from the administrator and use that to key an hmac you use for key derivation. In practice that's probably secure, except that it doesn't work with smart cards/cryptographic security modules, and that using a private key other than as a private key will make people twitchy. I now at least understand what you're trying to do, and don't have anything specifically better to offer. --Sam
On Mar 31, 2015, at 1:53 PM, Sam Hartman <hartmans@mit.edu> wrote:
So, I'd handle this by providing a utility to generate a strong random key and copy that between servers.
Which means that the systems have to communicate, and there's one more step to getting it to work.
Alan says something about a per-user ticket session key. You don't need that; you can have the same encryption key per-cluster, provided that you both encrypt and MAC and you don't do something horrible with how you encrypt things like reuse counters or nonces.
I have no idea how the session tickets are encrypted. That's the responsibility of the TLS people.
You're assuming that if I sign the same data twice the signature will be the same. That's true for RSA with a particular old type of padding. That is not generally true of public key signatures. I can't remember off the top of my head if it is a desirable security property that signing the same item multiple times generates distinct signatures or not.
Good point.
Hashing the signature definitely makes it better. The enginex design really scares me.
My updated recommendation to Arran is to simply do: key = hmac_sha256(server key, user identifier) Which should still be secure, easy to derive, and hard to crack.
Besides what I mentioned above , you could take the private key itself plus the input from the administrator and use that to key an hmac you use for key derivation. In practice that's probably secure, except that it doesn't work with smart cards/cryptographic security modules, and that using a private key other than as a private key will make people twitchy.
Yeah... that's life. Alan DeKok.
On 31 Mar 2015, at 15:27, Alan DeKok <aland@deployingradius.com> wrote:
On Mar 31, 2015, at 1:53 PM, Sam Hartman <hartmans@mit.edu> wrote:
So, I'd handle this by providing a utility to generate a strong random key and copy that between servers.
Which means that the systems have to communicate, and there's one more step to getting it to work.
Agreed.
Hashing the signature definitely makes it better. The enginex design really scares me.
My updated recommendation to Arran is to simply do:
key = hmac_sha256(server key, user identifier)
Call it an administrator key. It's not necessarily a user ID. It may have nothing to do with the request. It may be the thing that changes in order to implement key rotation. It's left up to the administrator to set. If they don't care so much about security, it could just be static. The likelihood of the private key being compromised is low. OTOH it could be a call out to the rlm_cache xlat function, which could use the rlm_rest xlat function to fetch a key from some central key generation and rotation service. The point is to accommodate the security requirements of different users without allowing them to shoot themselves in the foot.
Which should still be secure, easy to derive, and hard to crack.
Going to try out this, and see whether the generated keys are the same over multiple calls. https://www.openssl.org/docs/crypto/EVP_PKEY_derive.html The result of that could be used to key a HMAC of the administrator provided data. The hashing should resolve any issues with abusing EVP_PKEY_derive (by using it with both the server's private and public keys). With the first method I suggested, the signature did appear to be consistent with RSA keys and OpenSSL 1.0.1f, using the default engine and SHA256 as the digest. But it looks like for DH and EC the signature would change each time. So for OpenSSL < 1.0.0 the above hmac_sha256 would probably be ok. -Arran Arran Cudbard-Bell <a.cudbardb@freeradius.org> FreeRADIUS development team FD31 3077 42EC 7FCD 32FE 5EE2 56CF 27F9 30A8 CAA2
"Arran" == Arran Cudbard-Bell <a.cudbardb@freeradius.org> writes:
>> On 31 Mar 2015, at 15:27, Alan DeKok <aland@deployingradius.com> wrote: Well, they don't have to communicate, but an admin has to copy a file around once. Just like they do the private key. However, hmac(private_key, admin_identifier) will work.
participants (3)
-
Alan DeKok -
Arran Cudbard-Bell -
Sam Hartman