From f5435c74b7ce908343a9bd502a9d8f5f2d066faf Mon Sep 17 00:00:00 2001 From: Lionel Sambuc Date: Tue, 18 Dec 2012 11:01:53 +0100 Subject: [PATCH] Updating lib/libcrypt Change-Id: I4dc5ca7c86abc5295ffc57386a14dd1d790fd489 --- lib/libcrypt/Makefile | 2 - lib/libcrypt/bcrypt.c | 64 ++++++++++++++++--------------- lib/libcrypt/crypt-sha1.c | 30 +++++++-------- lib/libcrypt/crypt.3 | 67 ++++++++++++++++++++++++++++---- lib/libcrypt/crypt.c | 78 ++++++++++++++++++++++++++++---------- lib/libcrypt/hmac.c | 8 ++-- lib/libcrypt/md5crypt.c | 26 ++++--------- lib/libcrypt/shlib_version | 3 ++ releasetools/nbsd_ports | 2 +- 9 files changed, 180 insertions(+), 100 deletions(-) diff --git a/lib/libcrypt/Makefile b/lib/libcrypt/Makefile index 42ad3b1f6..4ff3f38c1 100644 --- a/lib/libcrypt/Makefile +++ b/lib/libcrypt/Makefile @@ -1,8 +1,6 @@ # $NetBSD: Makefile,v 1.24 2012/08/10 04:30:47 joerg Exp $ USE_SHLIBDIR= yes -#LSC MINIX Until the library gets updated -NOGCCERROR=yes LIB= crypt diff --git a/lib/libcrypt/bcrypt.c b/lib/libcrypt/bcrypt.c index 421d91fc3..106b1edb6 100644 --- a/lib/libcrypt/bcrypt.c +++ b/lib/libcrypt/bcrypt.c @@ -1,4 +1,4 @@ -/* $NetBSD: bcrypt.c,v 1.9 2006/10/27 19:39:11 drochner Exp $ */ +/* $NetBSD: bcrypt.c,v 1.17 2012/08/30 12:16:49 drochner Exp $ */ /* $OpenBSD: bcrypt.c,v 1.16 2002/02/19 19:39:36 millert Exp $ */ /* @@ -46,7 +46,7 @@ * */ #include -__RCSID("$NetBSD: bcrypt.c,v 1.9 2006/10/27 19:39:11 drochner Exp $"); +__RCSID("$NetBSD: bcrypt.c,v 1.17 2012/08/30 12:16:49 drochner Exp $"); #include #include @@ -66,7 +66,7 @@ __RCSID("$NetBSD: bcrypt.c,v 1.9 2006/10/27 19:39:11 drochner Exp $"); #define BCRYPT_VERSION '2' #define BCRYPT_MAXSALT 16 /* Precomputation is just so nice */ -#define BCRYPT_MAXSALTLEN (BCRYPT_MAXSALT * 4 / 3 + 1) +#define BCRYPT_MAXSALTLEN (7 + (BCRYPT_MAXSALT * 4 + 2) / 3 + 1) #define BCRYPT_BLOCKS 6 /* Ciphertext blocks */ #define BCRYPT_MINROUNDS 16 /* we have log2(rounds) in salt */ @@ -77,7 +77,6 @@ static void decode_base64(u_int8_t *, u_int16_t, const u_int8_t *); char *__bcrypt(const char *, const char *); /* XXX */ static char encrypted[_PASSWORD_LEN]; -static char error[] = ":"; static const u_int8_t Base64Code[] = "./ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"; @@ -175,13 +174,10 @@ __gensalt_blowfish(char *salt, size_t saltlen, const char *option) if (errno == ERANGE && nrounds == ULONG_MAX) return -1; - if (nrounds > 255) { - errno = EINVAL; - return -1; - } - if (nrounds < 4) nrounds = 4; + else if (nrounds > 31) + nrounds = 31; for (i = 0; i < BCRYPT_MAXSALT; i++) { if (i % 4 == 0) @@ -214,9 +210,7 @@ bcrypt_gensalt(u_int8_t log_rounds) i.e. $2$04$iwouldntknowwhattosayetKdJ6iFtacBqJdKe6aW7ou */ char * -__bcrypt(key, salt) - const char *key; - const char *salt; +__bcrypt(const char *key, const char *salt) { blf_ctx state; u_int32_t rounds, i, k; @@ -225,26 +219,26 @@ __bcrypt(key, salt) u_int8_t ciphertext[4 * BCRYPT_BLOCKS] = "OrpheanBeholderScryDoubt"; u_int8_t csalt[BCRYPT_MAXSALT]; u_int32_t cdata[BCRYPT_BLOCKS]; + int n; + size_t len; /* Discard "$" identifier */ salt++; - if (*salt > BCRYPT_VERSION) { - /* How do I handle errors ? Return ':' */ - return error; - } + if (*salt > BCRYPT_VERSION) + return NULL; /* Check for minor versions */ if (salt[1] != '$') { - switch (salt[1]) { - case 'a': - /* 'ab' should not yield the same as 'abab' */ - minor = salt[1]; - salt++; - break; - default: - return error; - } + switch (salt[1]) { + case 'a': + /* 'ab' should not yield the same as 'abab' */ + minor = salt[1]; + salt++; + break; + default: + return NULL; + } } else minor = 0; @@ -253,22 +247,31 @@ __bcrypt(key, salt) if (salt[2] != '$') /* Out of sync with passwd entry */ - return error; + return NULL; /* Computer power doesn't increase linear, 2^x should be fine */ - if ((rounds = (u_int32_t) 1 << (logr = atoi(salt))) < BCRYPT_MINROUNDS) - return error; + n = atoi(salt); + if (n > 31 || n < 0) + return NULL; + logr = (u_int8_t)n; + if ((rounds = (u_int32_t) 1 << logr) < BCRYPT_MINROUNDS) + return NULL; /* Discard num rounds + "$" identifier */ salt += 3; if (strlen(salt) * 3 / 4 < BCRYPT_MAXSALT) - return error; + return NULL; /* We dont want the base64 salt but the raw data */ decode_base64(csalt, BCRYPT_MAXSALT, (const u_int8_t *)salt); salt_len = BCRYPT_MAXSALT; - key_len = strlen(key) + (minor >= 'a' ? 1 : 0); + len = strlen(key); + if (len > 72) + key_len = 72; + else + key_len = (uint8_t)len; + key_len += minor >= 'a' ? 1 : 0; /* Setting up S-Boxes and Subkeys */ Blowfish_initstate(&state); @@ -311,6 +314,7 @@ __bcrypt(key, salt) encode_base64((u_int8_t *) encrypted + i + 3, csalt, BCRYPT_MAXSALT); encode_base64((u_int8_t *) encrypted + strlen(encrypted), ciphertext, 4 * BCRYPT_BLOCKS - 1); + __explicit_bzero(&state, sizeof(state)); return encrypted; } diff --git a/lib/libcrypt/crypt-sha1.c b/lib/libcrypt/crypt-sha1.c index a084dfd91..4b6c095e6 100644 --- a/lib/libcrypt/crypt-sha1.c +++ b/lib/libcrypt/crypt-sha1.c @@ -1,4 +1,4 @@ -/* $NetBSD: crypt-sha1.c,v 1.3 2006/10/27 18:22:56 drochner Exp $ */ +/* $NetBSD: crypt-sha1.c,v 1.5 2012/08/30 12:16:49 drochner Exp $ */ /* * Copyright (c) 2004, Juniper Networks, Inc. @@ -31,7 +31,7 @@ #include #if !defined(lint) -__RCSID("$NetBSD: crypt-sha1.c,v 1.3 2006/10/27 18:22:56 drochner Exp $"); +__RCSID("$NetBSD: crypt-sha1.c,v 1.5 2012/08/30 12:16:49 drochner Exp $"); #endif /* not lint */ #include @@ -122,7 +122,7 @@ __crypt_sha1 (const char *pw, const char *salt) static unsigned char hmac_buf[SHA1_SIZE]; static char passwd[(2 * sizeof(SHA1_MAGIC)) + CRYPT_SHA1_SALT_LENGTH + SHA1_SIZE]; - char *sp; + const char *sp; char *ep; unsigned long ul; int sl; @@ -136,26 +136,25 @@ __crypt_sha1 (const char *pw, const char *salt) * $$$salt[$] * If it does not start with $ we use our default iterations. */ - sp = __UNCONST(salt); /* If it starts with the magic string, then skip that */ - if (!strncmp(sp, magic, strlen(magic))) { - sp += strlen(magic); + if (!strncmp(salt, magic, strlen(magic))) { + salt += strlen(magic); /* and get the iteration count */ - iterations = strtoul(sp, &ep, 10); + iterations = strtoul(salt, &ep, 10); if (*ep != '$') return NULL; /* invalid input */ - sp = ep + 1; /* skip over the '$' */ + salt = ep + 1; /* skip over the '$' */ } else { iterations = __crypt_sha1_iterations(0); } /* It stops at the next '$', max CRYPT_SHA1_ITERATIONS chars */ - for (ep = sp; *ep && *ep != '$' && ep < (sp + CRYPT_SHA1_ITERATIONS); ep++) + for (sp = salt; *sp && *sp != '$' && sp < (salt + CRYPT_SHA1_ITERATIONS); sp++) continue; /* Get the length of the actual salt */ - sl = ep - sp; + sl = sp - salt; pl = strlen(pw); /* @@ -163,18 +162,17 @@ __crypt_sha1 (const char *pw, const char *salt) * Prime the pump with */ dl = snprintf(passwd, sizeof (passwd), "%.*s%s%u", - sl, sp, magic, iterations); + sl, salt, magic, iterations); /* * Then hmac using as key, and repeat... */ - ep = __UNCONST(pw); /* keep gcc happy */ - __hmac_sha1(passwd, dl, ep, pl, hmac_buf); + __hmac_sha1(passwd, dl, pw, pl, hmac_buf); for (i = 1; i < iterations; i++) { - __hmac_sha1(hmac_buf, SHA1_SIZE, ep, pl, hmac_buf); + __hmac_sha1(hmac_buf, SHA1_SIZE, pw, pl, hmac_buf); } /* Now output... */ pl = snprintf(passwd, sizeof(passwd), "%s%u$%.*s$", - magic, iterations, sl, sp); + magic, iterations, sl, salt); ep = passwd + pl; /* Every 3 bytes of hash gives 24 bits which is 4 base64 chars */ @@ -192,7 +190,7 @@ __crypt_sha1 (const char *pw, const char *salt) *ep = '\0'; /* Don't leave anything around in vm they could use. */ - memset(hmac_buf, 0, sizeof hmac_buf); + __explicit_bzero(hmac_buf, sizeof hmac_buf); return passwd; } diff --git a/lib/libcrypt/crypt.3 b/lib/libcrypt/crypt.3 index fa45652b3..b6da1da7d 100644 --- a/lib/libcrypt/crypt.3 +++ b/lib/libcrypt/crypt.3 @@ -1,4 +1,4 @@ -.\" $NetBSD: crypt.3,v 1.20 2005/09/05 03:37:15 hubertf Exp $ +.\" $NetBSD: crypt.3,v 1.27 2012/03/23 18:08:35 njoly Exp $ .\" .\" Copyright (c) 1989, 1991, 1993 .\" The Regents of the University of California. All rights reserved. @@ -29,7 +29,7 @@ .\" .\" @(#)crypt.3 8.2 (Berkeley) 12/11/93 .\" -.Dd September 4, 2005 +.Dd January 1, 2012 .Dt CRYPT 3 .Os .Sh NAME @@ -43,8 +43,8 @@ .Lb libcrypt .Sh SYNOPSIS .In unistd.h -.Ft char -.Fn *crypt "const char *key" "const char *setting" +.Ft "char *" +.Fn crypt "const char *key" "const char *setting" .Ft int .Fn encrypt "char *block" "int flag" .Ft int @@ -137,7 +137,7 @@ of the followed by the encoded 64-bit encryption. .Pp For compatibility with historical versions of -.Xr crypt 3 , +.Fn crypt , the .Ar setting may consist of 2 bytes of salt, encoded as above, in which case an @@ -244,7 +244,9 @@ for interpretation. .Ss "Blowfish" crypt The .Tn Blowfish -version of crypt has 128 bits of +version of +.Fn crypt +has 128 bits of .Fa salt in order to make building dictionaries of common passwords space consuming. The initial state of the @@ -281,7 +283,49 @@ for interpretation. .Sh RETURN VALUES The function .Fn crypt -returns a pointer to the encrypted value on success and NULL on failure. +returns a pointer to the encrypted value on success. +.Pp +The behavior of +.Fn crypt +on errors isn't well standardized. +Some implementations simply can't fail (unless the process dies, in which +case they obviously can't return), others return +.Dv NULL +or a fixed string. +Most implementations don't set +.Va errno , +but some do. +.St -susv2 +specifies +only returning +.Dv NULL +and setting +.Va errno +as a valid behavior, and defines +only one possible error +.Er ( ENOSYS , +.Dq "The functionality is not supported on this implementation." ) +Unfortunately, most existing applications aren't prepared to handle +.Dv NULL +returns from +.Fn crypt . +The description below corresponds to this implementation of +.Fn crypt +only. +The behavior may change to match standards, other implementations or existing +applications. +.Pp +.Fn crypt +may only fail (and return) when passed an invalid or unsupported +.Fa setting , +in which case it returns a pointer to a magic string that is shorter than 13 +characters and is guaranteed to differ from +.Fa setting . +This behavior is safe for older applications which assume that +.Fn crypt +can't fail, when both setting new passwords and authenticating against +existing password hashes. +.Pp The functions .Fn setkey , .Fn encrypt , @@ -352,3 +396,12 @@ a pointer to that object. Subsequent calls to .Fn crypt will modify the same object. +.Pp +Before +.Nx 6.0 +.Fn crypt +returned either +.Dv NULL +or +.Dv \&: +on error. diff --git a/lib/libcrypt/crypt.c b/lib/libcrypt/crypt.c index 6050963a6..ba8cdec99 100644 --- a/lib/libcrypt/crypt.c +++ b/lib/libcrypt/crypt.c @@ -1,4 +1,4 @@ -/* $NetBSD: crypt.c,v 1.28 2009/05/01 00:28:17 perry Exp $ */ +/* $NetBSD: crypt.c,v 1.33 2011/12/28 03:13:09 christos Exp $ */ /* * Copyright (c) 1989, 1993 @@ -37,7 +37,7 @@ #if 0 static char sccsid[] = "@(#)crypt.c 8.1.1.1 (Berkeley) 8/18/93"; #else -__RCSID("$NetBSD: crypt.c,v 1.28 2009/05/01 00:28:17 perry Exp $"); +__RCSID("$NetBSD: crypt.c,v 1.33 2011/12/28 03:13:09 christos Exp $"); #endif #endif /* not lint */ @@ -445,8 +445,6 @@ static const unsigned char itoa64[] = /* 0..63 => ascii-64 */ /* ===== Tables that are initialized at run time ==================== */ -static unsigned char a64toi[128]; /* ascii-64 => 0..63 */ - /* Initial key schedule permutation */ static C_block PC1ROT[64/CHUNKBITS][1<= 'a') + retval = sch - ('a' - 38); + else if (sch >= 'A') + retval = sch - ('A' - 12); + else + retval = sch - '.'; + + return retval & 0x3f; +} + +/* + * When we choose to "support" invalid salts, nevertheless disallow those + * containing characters that would violate the passwd file format. + */ +static inline int +ascii_is_unsafe(char ch) +{ + return !ch || ch == '\n' || ch == ':'; +} /* * Return a pointer to static data consisting of the "setting" * followed by an encryption produced by the "key" and "setting". */ -char * -crypt(const char *key, const char *setting) +static char * +__crypt(const char *key, const char *setting) { char *encp; int32_t i; @@ -502,7 +529,7 @@ crypt(const char *key, const char *setting) key++; keyblock.b[i] = t; } - if (des_setkey((char *)keyblock.b)) /* also initializes "a64toi" */ + if (des_setkey((char *)keyblock.b)) return (NULL); encp = &cryptresult[0]; @@ -529,11 +556,14 @@ crypt(const char *key, const char *setting) /* get iteration count */ num_iter = 0; for (i = 4; --i >= 0; ) { - if ((t = (unsigned char)setting[i]) == '\0') - t = '.'; - encp[i] = t; - num_iter = (num_iter<<6) | a64toi[t]; + int value = ascii_to_bin(setting[i]); + if (itoa64[value] != setting[i]) + return NULL; + encp[i] = setting[i]; + num_iter = (num_iter << 6) | value; } + if (num_iter == 0) + return NULL; setting += 4; encp += 4; salt_size = 4; @@ -541,14 +571,17 @@ crypt(const char *key, const char *setting) default: num_iter = 25; salt_size = 2; + if (ascii_is_unsafe(setting[0]) || ascii_is_unsafe(setting[1])) + return NULL; } salt = 0; for (i = salt_size; --i >= 0; ) { - if ((t = (unsigned char)setting[i]) == '\0') - t = '.'; - encp[i] = t; - salt = (salt<<6) | a64toi[t]; + int value = ascii_to_bin(setting[i]); + if (salt_size > 2 && itoa64[value] != setting[i]) + return NULL; + encp[i] = setting[i]; + salt = (salt << 6) | value; } encp += salt_size; if (des_cipher((char *)(void *)&constdatablock, @@ -580,6 +613,15 @@ crypt(const char *key, const char *setting) return (cryptresult); } +char * +crypt(const char *key, const char *salt) +{ + char *res = __crypt(key, salt); + if (res) + return res; + /* How do I handle errors ? Return "*0" or "*1" */ + return __UNCONST(salt[0] == '*' && salt[1] == '0' ? "*1" : "*0"); +} /* * The Key Schedule, filled in by des_setkey() or setkey(). @@ -750,12 +792,6 @@ init_des(void) int tableno; static unsigned char perm[64], tmp32[32]; /* "static" for speed */ - /* - * table that converts chars "./0-9A-Za-z"to integers 0-63. - */ - for (i = 0; i < 64; i++) - a64toi[itoa64[i]] = i; - /* * PC1ROT - bit reverse, then PC1, then Rotate, then PC2. */ diff --git a/lib/libcrypt/hmac.c b/lib/libcrypt/hmac.c index fe2559455..127da86a5 100644 --- a/lib/libcrypt/hmac.c +++ b/lib/libcrypt/hmac.c @@ -1,4 +1,4 @@ -/* $NetBSD: hmac.c,v 1.2 2009/01/18 12:15:27 lukem Exp $ */ +/* $NetBSD: hmac.c,v 1.3 2011/05/16 10:39:12 drochner Exp $ */ /* * Copyright (c) 2004, Juniper Networks, Inc. @@ -42,7 +42,7 @@ */ #include #if !defined(lint) -__RCSID("$NetBSD: hmac.c,v 1.2 2009/01/18 12:15:27 lukem Exp $"); +__RCSID("$NetBSD: hmac.c,v 1.3 2011/05/16 10:39:12 drochner Exp $"); #endif /* not lint */ #include @@ -70,9 +70,9 @@ HMAC_FUNC (const unsigned char *text, size_t text_len, { HASH_CTX context; /* Inner padding key XOR'd with ipad */ - unsigned char k_ipad[HMAC_BLOCKSZ + 1]; + unsigned char k_ipad[HMAC_BLOCKSZ]; /* Outer padding key XOR'd with opad */ - unsigned char k_opad[HMAC_BLOCKSZ + 1]; + unsigned char k_opad[HMAC_BLOCKSZ]; /* HASH(key) if needed */ unsigned char tk[HASH_LENGTH]; size_t i; diff --git a/lib/libcrypt/md5crypt.c b/lib/libcrypt/md5crypt.c index 4b04da11d..74f9352ac 100644 --- a/lib/libcrypt/md5crypt.c +++ b/lib/libcrypt/md5crypt.c @@ -1,4 +1,4 @@ -/* $NetBSD: md5crypt.c,v 1.9 2007/01/17 23:24:22 hubertf Exp $ */ +/* $NetBSD: md5crypt.c,v 1.12 2012/08/30 12:16:49 drochner Exp $ */ /* * ---------------------------------------------------------------------------- @@ -15,38 +15,22 @@ #include #if !defined(lint) -__RCSID("$NetBSD: md5crypt.c,v 1.9 2007/01/17 23:24:22 hubertf Exp $"); +__RCSID("$NetBSD: md5crypt.c,v 1.12 2012/08/30 12:16:49 drochner Exp $"); #endif /* not lint */ -/* - * NOTE: We are also built for inclusion in libcrypto; when built for that - * environment, use the libcrypto versions of the MD5 routines, so save - * having to pull two versions into the same program. - */ - #include #include #include -#ifdef libcrypto -#include -#else #include -#endif #include "crypt.h" #define MD5_MAGIC "$1$" #define MD5_MAGIC_LEN 3 -#ifdef libcrypto -#define INIT(x) MD5_Init((x)) -#define UPDATE(x, b, l) MD5_Update((x), (b), (l)) -#define FINAL(v, x) MD5_Final((v), (x)) -#else #define INIT(x) MD5Init((x)) #define UPDATE(x, b, l) MD5Update((x), (b), (l)) #define FINAL(v, x) MD5Final((v), (x)) -#endif /* @@ -117,6 +101,8 @@ __md5crypt(const char *pw, const char *salt) FINAL(final, &ctx); + /* memset(&ctx, 0, sizeof(ctx)); done by MD5Final() */ + /* * And now, just to make sure things don't run too fast. On a 60 MHz * Pentium this takes 34 msec, so you would need 30 seconds to build @@ -144,6 +130,8 @@ __md5crypt(const char *pw, const char *salt) FINAL(final, &ctx1); } + /* memset(&ctx1, 0, sizeof(ctx1)); done by MD5Final() */ + p = passwd + sl + MD5_MAGIC_LEN + 1; l = (final[ 0]<<16) | (final[ 6]<<8) | final[12]; __crypt_to64(p,l,4); p += 4; @@ -155,6 +143,6 @@ __md5crypt(const char *pw, const char *salt) *p = '\0'; /* Don't leave anything around in vm they could use. */ - memset(final, 0, sizeof(final)); + __explicit_bzero(final, sizeof(final)); return (passwd); } diff --git a/lib/libcrypt/shlib_version b/lib/libcrypt/shlib_version index 97c9f92d6..a67bb819c 100644 --- a/lib/libcrypt/shlib_version +++ b/lib/libcrypt/shlib_version @@ -1,2 +1,5 @@ +# $NetBSD: shlib_version,v 1.6 2009/01/11 03:07:47 christos Exp $ +# Remember to update distrib/sets/lists/base/shl.* when changing +# major=0 minor=0 diff --git a/releasetools/nbsd_ports b/releasetools/nbsd_ports index 672673d44..ef452a648 100644 --- a/releasetools/nbsd_ports +++ b/releasetools/nbsd_ports @@ -55,7 +55,7 @@ 2012/10/17 12:00:00,lib/csu 2012/10/17 12:00:00,lib/libbz2 2012/10/17 12:00:00,lib/libc -2009/05/01 00:28:17,lib/libcrypt +2012/10/17 12:00:00,lib/libcrypt 2012/10/17 12:00:00,lib/libcurses 2012/10/17 12:00:00,lib/libm 2011/09/30 22:08:19,lib/libprop