X-Git-Url: http://git.silcnet.org/gitweb/?p=silc.git;a=blobdiff_plain;f=lib%2Fsilccore%2Fsilcauth.c;h=38a1a961392e87fe668cd7110f48dc0418990780;hp=e66f9653834e69de3e69b0099bf82d4ef81a268d;hb=382d15d447b7a95390decfa783836ae4fe255b3d;hpb=6493ad0f849286d972031f20c6eed45140d5e0a7 diff --git a/lib/silccore/silcauth.c b/lib/silccore/silcauth.c index e66f9653..38a1a961 100644 --- a/lib/silccore/silcauth.c +++ b/lib/silccore/silcauth.c @@ -1,16 +1,15 @@ /* - silcauth.c + silcauth.c - Author: Pekka Riikonen + Author: Pekka Riikonen - Copyright (C) 2001 Pekka Riikonen + Copyright (C) 2001 - 2002 Pekka Riikonen This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - + the Free Software Foundation; version 2 of the License. + This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the @@ -30,72 +29,103 @@ /* Authentication Payload structure */ struct SilcAuthPayloadStruct { - uint16 len; - uint16 auth_method; - uint16 random_len; + SilcUInt16 len; + SilcUInt16 auth_method; + SilcUInt16 random_len; unsigned char *random_data; - uint16 auth_len; + SilcUInt16 auth_len; unsigned char *auth_data; }; /* Parses and returns Authentication Payload */ SilcAuthPayload silc_auth_payload_parse(const unsigned char *data, - uint32 data_len) + SilcUInt32 data_len) { SilcBufferStruct buffer; - SilcAuthPayload new; + SilcAuthPayload newp; int ret; SILC_LOG_DEBUG(("Parsing Authentication Payload")); silc_buffer_set(&buffer, (unsigned char *)data, data_len); - new = silc_calloc(1, sizeof(*new)); + newp = silc_calloc(1, sizeof(*newp)); + if (!newp) + return NULL; /* Parse the payload */ - ret = silc_buffer_unformat(&buffer, - SILC_STR_UI_SHORT(&new->len), - SILC_STR_UI_SHORT(&new->auth_method), - SILC_STR_UI16_NSTRING_ALLOC(&new->random_data, - &new->random_len), - SILC_STR_UI16_NSTRING_ALLOC(&new->auth_data, - &new->auth_len), + ret = silc_buffer_unformat(&buffer, + SILC_STR_UI_SHORT(&newp->len), + SILC_STR_UI_SHORT(&newp->auth_method), + SILC_STR_UI16_NSTRING_ALLOC(&newp->random_data, + &newp->random_len), + SILC_STR_UI16_NSTRING_ALLOC(&newp->auth_data, + &newp->auth_len), SILC_STR_END); if (ret == -1) { - silc_free(new); + silc_free(newp); return NULL; } - if (new->len != buffer.len) { - silc_auth_payload_free(new); + if (newp->len != buffer.len || + newp->random_len + newp->auth_len > buffer.len - 8) { + silc_auth_payload_free(newp); + return NULL; + } + + /* Authentication data must be provided */ + if (newp->auth_len < 1) { + silc_auth_payload_free(newp); return NULL; } /* If password authentication, random data must not be set */ - if (new->auth_method == SILC_AUTH_PASSWORD && new->random_len) { - silc_auth_payload_free(new); + if (newp->auth_method == SILC_AUTH_PASSWORD && newp->random_len) { + silc_auth_payload_free(newp); return NULL; } - return new; + /* If public key authentication, random data must be at least 128 bytes */ + if (newp->auth_method == SILC_AUTH_PUBLIC_KEY && newp->random_len < 128) { + silc_auth_payload_free(newp); + return NULL; + } + + return newp; } /* Encodes authentication payload into buffer and returns it */ SilcBuffer silc_auth_payload_encode(SilcAuthMethod method, const unsigned char *random_data, - uint16 random_len, + SilcUInt16 random_len, const unsigned char *auth_data, - uint16 auth_len) + SilcUInt16 auth_len) { SilcBuffer buffer; - uint32 len; + SilcUInt32 len; + unsigned char *autf8 = NULL; + SilcUInt32 autf8_len; SILC_LOG_DEBUG(("Encoding Authentication Payload")); + /* Passphrase MUST be UTF-8 encoded, encode if it is not */ + if (method == SILC_AUTH_PASSWORD && !silc_utf8_valid(auth_data, auth_len)) { + autf8_len = silc_utf8_encoded_len(auth_data, auth_len, 0); + if (!autf8_len) + return NULL; + autf8 = silc_calloc(autf8_len, sizeof(*autf8)); + auth_len = silc_utf8_encode(auth_data, auth_len, 0, autf8, autf8_len); + auth_data = (const unsigned char *)autf8; + } + len = 2 + 2 + 2 + random_len + 2 + auth_len; - buffer = silc_buffer_alloc(len); - silc_buffer_pull_tail(buffer, SILC_BUFFER_END(buffer)); + buffer = silc_buffer_alloc_size(len); + if (!buffer) { + silc_free(autf8); + return NULL; + } + silc_buffer_format(buffer, SILC_STR_UI_SHORT(len), SILC_STR_UI_SHORT(method), @@ -105,6 +135,7 @@ SilcBuffer silc_auth_payload_encode(SilcAuthMethod method, SILC_STR_UI_XNSTRING(auth_data, auth_len), SILC_STR_END); + silc_free(autf8); return buffer; } @@ -132,10 +163,10 @@ SilcAuthMethod silc_auth_get_method(SilcAuthPayload payload) return payload->auth_method; } -/* Get the authentication data */ +/* Get the authentication data. If this is passphrase it is UTF-8 encoded. */ unsigned char *silc_auth_get_data(SilcAuthPayload payload, - uint32 *auth_len) + SilcUInt32 *auth_len) { if (auth_len) *auth_len = payload->auth_len; @@ -153,14 +184,14 @@ unsigned char *silc_auth_get_data(SilcAuthPayload payload, dictates. */ static unsigned char * -silc_auth_public_key_encode_data(SilcPublicKey public_key, - const unsigned char *random, - uint32 random_len, const void *id, - SilcIdType type, uint32 *ret_len) +silc_auth_public_key_encode_data(SilcPublicKey public_key, + const unsigned char *randomdata, + SilcUInt32 random_len, const void *id, + SilcIdType type, SilcUInt32 *ret_len) { SilcBuffer buf; unsigned char *pk, *id_data, *ret; - uint32 pk_len, id_len; + SilcUInt32 pk_len, id_len; pk = silc_pkcs_public_key_encode(public_key, &pk_len); if (!pk) @@ -173,20 +204,26 @@ silc_auth_public_key_encode_data(SilcPublicKey public_key, } id_len = silc_id_get_len(id, type); - buf = silc_buffer_alloc(random_len + id_len + pk_len); - silc_buffer_pull_tail(buf, SILC_BUFFER_END(buf)); + buf = silc_buffer_alloc_size(random_len + id_len + pk_len); + if (!buf) { + silc_free(pk); + silc_free(id_data); + return NULL; + } silc_buffer_format(buf, - SILC_STR_UI_XNSTRING(random, random_len), + SILC_STR_UI_XNSTRING(randomdata, random_len), SILC_STR_UI_XNSTRING(id_data, id_len), SILC_STR_UI_XNSTRING(pk, pk_len), SILC_STR_END); - - ret = silc_calloc(buf->len + 1, sizeof(*ret)); - memcpy(ret, buf->data, buf->len); + + ret = silc_memdup(buf->data, buf->len); + if (!ret) + return NULL; if (ret_len) *ret_len = buf->len; + silc_buffer_clear(buf); silc_buffer_free(buf); silc_free(id_data); silc_free(pk); @@ -200,32 +237,35 @@ silc_auth_public_key_encode_data(SilcPublicKey public_key, SilcBuffer silc_auth_public_key_auth_generate(SilcPublicKey public_key, SilcPrivateKey private_key, - SilcHash hash, + SilcRng rng, SilcHash hash, const void *id, SilcIdType type) { - unsigned char *random; - unsigned char auth_data[1024]; - uint32 auth_len; + unsigned char *randomdata; + unsigned char auth_data[2048 + 1]; + SilcUInt32 auth_len; unsigned char *tmp; - uint32 tmp_len; + SilcUInt32 tmp_len; SilcBuffer buf; SilcPKCS pkcs; SILC_LOG_DEBUG(("Generating Authentication Payload with data")); /* Get 256 bytes of random data */ - random = silc_rng_global_get_rn_data(256); - if (!random) + if (rng) + randomdata = silc_rng_get_rn_data(rng, 256); + else + randomdata = silc_rng_global_get_rn_data(256); + if (!randomdata) return NULL; - + /* Encode the auth data */ - tmp = silc_auth_public_key_encode_data(public_key, random, 256, id, type, - &tmp_len); + tmp = silc_auth_public_key_encode_data(public_key, randomdata, 256, id, + type, &tmp_len); if (!tmp) return NULL; /* Allocate PKCS object */ - if (!silc_pkcs_alloc(public_key->name, &pkcs)) { + if (!silc_pkcs_alloc(private_key->name, &pkcs)) { memset(tmp, 0, tmp_len); silc_free(tmp); return NULL; @@ -234,25 +274,26 @@ SilcBuffer silc_auth_public_key_auth_generate(SilcPublicKey public_key, silc_pkcs_private_key_set(pkcs, private_key); /* Compute the hash and the signature. */ - if (!silc_pkcs_sign_with_hash(pkcs, hash, tmp, tmp_len, auth_data, + if (silc_pkcs_get_key_len(pkcs) / 8 > sizeof(auth_data) - 1 || + !silc_pkcs_sign_with_hash(pkcs, hash, tmp, tmp_len, auth_data, &auth_len)) { - memset(random, 0, 256); + memset(randomdata, 0, 256); memset(tmp, 0, tmp_len); silc_free(tmp); - silc_free(random); + silc_free(randomdata); silc_pkcs_free(pkcs); return NULL; } /* Encode Authentication Payload */ - buf = silc_auth_payload_encode(SILC_AUTH_PUBLIC_KEY, random, 256, + buf = silc_auth_payload_encode(SILC_AUTH_PUBLIC_KEY, randomdata, 256, auth_data, auth_len); memset(tmp, 0, tmp_len); memset(auth_data, 0, sizeof(auth_data)); - memset(random, 0, 256); + memset(randomdata, 0, 256); silc_free(tmp); - silc_free(random); + silc_free(randomdata); silc_pkcs_free(pkcs); return buf; @@ -266,14 +307,14 @@ bool silc_auth_public_key_auth_verify(SilcAuthPayload payload, const void *id, SilcIdType type) { unsigned char *tmp; - uint32 tmp_len; + SilcUInt32 tmp_len; SilcPKCS pkcs; SILC_LOG_DEBUG(("Verifying authentication data")); /* Encode auth data */ - tmp = silc_auth_public_key_encode_data(public_key, payload->random_data, - payload->random_len, + tmp = silc_auth_public_key_encode_data(public_key, payload->random_data, + payload->random_len, id, type, &tmp_len); if (!tmp) { SILC_LOG_DEBUG(("Authentication failed")); @@ -311,8 +352,8 @@ bool silc_auth_public_key_auth_verify(SilcAuthPayload payload, /* Same as above but the payload is not parsed yet. This will parse it. */ bool silc_auth_public_key_auth_verify_data(const unsigned char *payload, - uint32 payload_len, - SilcPublicKey public_key, + SilcUInt32 payload_len, + SilcPublicKey public_key, SilcHash hash, const void *id, SilcIdType type) { @@ -325,7 +366,7 @@ bool silc_auth_public_key_auth_verify_data(const unsigned char *payload, return FALSE; } - ret = silc_auth_public_key_auth_verify(auth_payload, public_key, hash, + ret = silc_auth_public_key_auth_verify(auth_payload, public_key, hash, id, type); silc_auth_payload_free(auth_payload); @@ -333,7 +374,7 @@ bool silc_auth_public_key_auth_verify_data(const unsigned char *payload, return ret; } -/* Verifies the authentication data directly from the Authentication +/* Verifies the authentication data directly from the Authentication Payload. Supports all authentication methods. If the authentication method is passphrase based then the `auth_data' and `auth_data_len' are the passphrase and its length. If the method is public key @@ -341,12 +382,12 @@ bool silc_auth_public_key_auth_verify_data(const unsigned char *payload, `auth_data_len' is ignored. */ bool silc_auth_verify(SilcAuthPayload payload, SilcAuthMethod auth_method, - const void *auth_data, uint32 auth_data_len, + const void *auth_data, SilcUInt32 auth_data_len, SilcHash hash, const void *id, SilcIdType type) { SILC_LOG_DEBUG(("Verifying authentication")); - if (auth_method != payload->auth_method) + if (!payload || auth_method != payload->auth_method) return FALSE; switch (payload->auth_method) { @@ -358,8 +399,14 @@ bool silc_auth_verify(SilcAuthPayload payload, SilcAuthMethod auth_method, case SILC_AUTH_PASSWORD: /* Passphrase based authentication. The `pkcs', `hash', `id' and `type' arguments are not needed. */ + + /* Sanity checks */ + if ((payload->auth_len == 0) || !auth_data || + payload->auth_len != auth_data_len) + break; + if (!memcmp(payload->auth_data, auth_data, auth_data_len)) { - SILC_LOG_DEBUG(("Authentication successful")); + SILC_LOG_DEBUG(("Passphrase Authentication successful")); return TRUE; } break; @@ -381,19 +428,20 @@ bool silc_auth_verify(SilcAuthPayload payload, SilcAuthMethod auth_method, /* Same as above but parses the authentication payload before verify. */ -bool silc_auth_verify_data(const unsigned char *payload, uint32 payload_len, +bool silc_auth_verify_data(const unsigned char *payload, + SilcUInt32 payload_len, SilcAuthMethod auth_method, const void *auth_data, - uint32 auth_data_len, SilcHash hash, + SilcUInt32 auth_data_len, SilcHash hash, const void *id, SilcIdType type) { SilcAuthPayload auth_payload; - int ret; + bool ret; auth_payload = silc_auth_payload_parse(payload, payload_len); - if (!auth_payload) + if (!auth_payload || (auth_payload->auth_len == 0)) return FALSE; - ret = silc_auth_verify(auth_payload, auth_method, auth_data, auth_data_len, + ret = silc_auth_verify(auth_payload, auth_method, auth_data, auth_data_len, hash, id, type); silc_auth_payload_free(auth_payload); @@ -409,52 +457,55 @@ bool silc_auth_verify_data(const unsigned char *payload, uint32 payload_len, /* The Key Agreement protocol structure */ struct SilcKeyAgreementPayloadStruct { - uint16 hostname_len; + SilcUInt16 hostname_len; unsigned char *hostname; - uint32 port; + SilcUInt32 port; }; /* Parses and returns an allocated Key Agreement payload. */ -SilcKeyAgreementPayload +SilcKeyAgreementPayload silc_key_agreement_payload_parse(const unsigned char *payload, - uint32 payload_len) + SilcUInt32 payload_len) { SilcBufferStruct buffer; - SilcKeyAgreementPayload new; + SilcKeyAgreementPayload newp; int ret; SILC_LOG_DEBUG(("Parsing Key Agreement Payload")); silc_buffer_set(&buffer, (unsigned char *)payload, payload_len); - new = silc_calloc(1, sizeof(*new)); + newp = silc_calloc(1, sizeof(*newp)); + if (!newp) + return NULL; /* Parse the payload */ - ret = silc_buffer_unformat(&buffer, - SILC_STR_UI16_NSTRING_ALLOC(&new->hostname, - &new->hostname_len), - SILC_STR_UI_INT(&new->port), + ret = silc_buffer_unformat(&buffer, + SILC_STR_UI16_NSTRING_ALLOC(&newp->hostname, + &newp->hostname_len), + SILC_STR_UI_INT(&newp->port), SILC_STR_END); if (ret == -1) { - silc_free(new); + silc_free(newp); return NULL; } - return new; + return newp; } /* Encodes the Key Agreement protocol and returns the encoded buffer */ SilcBuffer silc_key_agreement_payload_encode(const char *hostname, - uint32 port) + SilcUInt32 port) { SilcBuffer buffer; - uint32 len = hostname ? strlen(hostname) : 0; + SilcUInt32 len = hostname ? strlen(hostname) : 0; SILC_LOG_DEBUG(("Encoding Key Agreement Payload")); - buffer = silc_buffer_alloc(2 + len + 4); - silc_buffer_pull_tail(buffer, SILC_BUFFER_END(buffer)); + buffer = silc_buffer_alloc_size(2 + len + 4); + if (!buffer) + return NULL; silc_buffer_format(buffer, SILC_STR_UI_SHORT(len), SILC_STR_UI_XNSTRING(hostname, len), @@ -483,7 +534,7 @@ char *silc_key_agreement_get_hostname(SilcKeyAgreementPayload payload) /* Returns the port in the payload */ -uint32 silc_key_agreement_get_port(SilcKeyAgreementPayload payload) +SilcUInt32 silc_key_agreement_get_port(SilcKeyAgreementPayload payload) { return payload->port; }