]> git.kaiwu.me - nginx.git/commitdiff
"$apr1", "{PLAIN}", and "{SSHA}" password methods in auth basic module
authorIgor Sysoev <igor@sysoev.ru>
Mon, 16 May 2011 14:54:50 +0000 (14:54 +0000)
committerIgor Sysoev <igor@sysoev.ru>
Mon, 16 May 2011 14:54:50 +0000 (14:54 +0000)
patch by Maxim Dounin

auto/lib/conf
auto/lib/sha1/conf
auto/modules
auto/sources
src/core/ngx_crypt.c [new file with mode: 0644]
src/core/ngx_crypt.h [new file with mode: 0644]
src/http/modules/ngx_http_auth_basic_module.c
src/os/unix/ngx_user.c
src/os/unix/ngx_user.h
src/os/win32/ngx_user.c
src/os/win32/ngx_user.h

index f89d922f8702871c74116b79975cbf0159c61ab6..357e7810d69ffa8de70ab427bb724c46626e9061 100644 (file)
@@ -43,6 +43,7 @@ if [ $USE_SHA1 = YES ]; then
 
     if [ $USE_OPENSSL = YES ]; then
         have=NGX_HAVE_OPENSSL_SHA1_H . auto/have
+        have=NGX_HAVE_SHA1 . auto/have
         SHA1=YES
         SHA1_LIB=OpenSSL
 
index 888537779d6d4bb9d0af7b4af59f4a68d2ba17bd..af3d3fba2e72ac33c2aab6e0acf431ace42ccff3 100644 (file)
@@ -4,6 +4,7 @@
 
 if [ $SHA1 != NONE ]; then
 
+    have=NGX_HAVE_SHA1 . auto/have
     CORE_INCS="$CORE_INCS $SHA1"
 
     case "$NGX_CC_NAME" in
@@ -41,7 +42,7 @@ else
         # FreeBSD
 
         ngx_feature="sha1 in system md library"
-        ngx_feature_name=
+        ngx_feature_name=NGX_HAVE_SHA1
         ngx_feature_run=no
         ngx_feature_incs="#include <sha.h>"
         ngx_feature_path=
index 9ac1ddd071a895e1151068dc393bbabb4cebe7cc..80c557c2b099e2e6a3c35560edc6060f47759dca 100644 (file)
@@ -197,6 +197,8 @@ if [ $HTTP_RANDOM_INDEX = YES ]; then
 fi
 
 if [ $HTTP_AUTH_BASIC = YES ]; then
+    USE_MD5=YES
+    USE_SHA1=YES
     have=NGX_CRYPT . auto/have
     HTTP_MODULES="$HTTP_MODULES $HTTP_AUTH_BASIC_MODULE"
     HTTP_SRCS="$HTTP_SRCS $HTTP_AUTH_BASIC_SRCS"
index 07809baaea207eaaec3e35ed3d24b8d361a82e32..0ab99440cdb37f89c33fc011ae6cedda35b214b3 100644 (file)
@@ -34,7 +34,8 @@ CORE_DEPS="src/core/nginx.h \
            src/core/ngx_cycle.h \
            src/core/ngx_conf_file.h \
            src/core/ngx_resolver.h \
-           src/core/ngx_open_file_cache.h"
+           src/core/ngx_open_file_cache.h \
+           src/core/ngx_crypt.h"
 
 
 CORE_SRCS="src/core/nginx.c \
@@ -64,7 +65,8 @@ CORE_SRCS="src/core/nginx.c \
            src/core/ngx_cpuinfo.c \
            src/core/ngx_conf_file.c \
            src/core/ngx_resolver.c \
-           src/core/ngx_open_file_cache.c"
+           src/core/ngx_open_file_cache.c \
+           src/core/ngx_crypt.c"
 
 
 REGEX_DEPS=src/core/ngx_regex.h
diff --git a/src/core/ngx_crypt.c b/src/core/ngx_crypt.c
new file mode 100644 (file)
index 0000000..2538cfc
--- /dev/null
@@ -0,0 +1,234 @@
+
+/*
+ * Copyright (C) Maxim Dounin
+ */
+
+
+#include <ngx_config.h>
+#include <ngx_core.h>
+#include <ngx_md5.h>
+#if (NGX_HAVE_SHA1)
+#include <ngx_sha1.h>
+#endif
+
+
+static ngx_int_t ngx_crypt_apr1(ngx_pool_t *pool, u_char *key, u_char *salt,
+    u_char **encrypted);
+static ngx_int_t ngx_crypt_plain(ngx_pool_t *pool, u_char *key, u_char *salt,
+    u_char **encrypted);
+
+#if (NGX_HAVE_SHA1)
+
+static ngx_int_t ngx_crypt_ssha(ngx_pool_t *pool, u_char *key, u_char *salt,
+    u_char **encrypted);
+
+#endif
+
+
+static u_char *ngx_crypt_to64(u_char *p, uint32_t v, size_t n);
+
+
+ngx_int_t
+ngx_crypt(ngx_pool_t *pool, u_char *key, u_char *salt, u_char **encrypted)
+{
+    if (ngx_strncmp(salt, "$apr1$", sizeof("$apr1$") - 1) == 0) {
+        return ngx_crypt_apr1(pool, key, salt, encrypted);
+
+    } else if (ngx_strncmp(salt, "{PLAIN}", sizeof("{PLAIN}") - 1) == 0) {
+        return ngx_crypt_plain(pool, key, salt, encrypted);
+
+#if (NGX_HAVE_SHA1)
+    } else if (ngx_strncmp(salt, "{SSHA}", sizeof("{SSHA}") - 1) == 0) {
+        return ngx_crypt_ssha(pool, key, salt, encrypted);
+#endif
+    }
+
+    /* fallback to libc crypt() */
+
+    return ngx_libc_crypt(pool, key, salt, encrypted);
+}
+
+
+static ngx_int_t
+ngx_crypt_apr1(ngx_pool_t *pool, u_char *key, u_char *salt, u_char **encrypted)
+{
+    ngx_int_t          n;
+    ngx_uint_t         i;
+    u_char            *p, *last, final[16];
+    size_t             saltlen, keylen;
+    ngx_md5_t          md5, ctx1;
+
+    /* Apache's apr1 crypt is Paul-Henning Kamp's md5 crypt with $apr1$ magic */
+
+    keylen = ngx_strlen(key);
+
+    /* true salt: no magic, max 8 chars, stop at first $ */
+
+    salt += sizeof("$apr1$") - 1;
+    last = salt + 8;
+    for (p = salt; *p && *p != '$' && p < last; p++) { /* void */ }
+    saltlen = p - salt;
+
+    /* hash key and salt */
+
+    ngx_md5_init(&md5);
+    ngx_md5_update(&md5, key, keylen);
+    ngx_md5_update(&md5, "$apr1$", sizeof("$apr1$") - 1);
+    ngx_md5_update(&md5, salt, saltlen);
+
+    ngx_md5_init(&ctx1);
+    ngx_md5_update(&ctx1, key, keylen);
+    ngx_md5_update(&ctx1, salt, saltlen);
+    ngx_md5_update(&ctx1, key, keylen);
+    ngx_md5_final(final, &ctx1);
+
+    for (n = keylen; n > 0; n -= 16) {
+        ngx_md5_update(&md5, final, n > 16 ? 16 : n);
+    }
+
+    ngx_memzero(final, sizeof(final));
+
+    for (i = keylen; i; i >>= 1) {
+        if (i & 1) {
+            ngx_md5_update(&md5, final, 1);
+
+        } else {
+            ngx_md5_update(&md5, key, 1);
+        }
+    }
+
+    ngx_md5_final(final, &md5);
+
+    for (i = 0; i < 1000; i++) {
+        ngx_md5_init(&ctx1);
+
+        if (i & 1) {
+            ngx_md5_update(&ctx1, key, keylen);
+
+        } else {
+            ngx_md5_update(&ctx1, final, 16);
+        }
+
+        if (i % 3) {
+            ngx_md5_update(&ctx1, salt, saltlen);
+        }
+
+        if (i % 7) {
+            ngx_md5_update(&ctx1, key, keylen);
+        }
+
+        if (i & 1) {
+            ngx_md5_update(&ctx1, final, 16);
+
+        } else {
+            ngx_md5_update(&ctx1, key, keylen);
+        }
+
+        ngx_md5_final(final, &ctx1);
+    }
+
+    /* output */
+
+    *encrypted = ngx_pnalloc(pool, sizeof("$apr1$") - 1 + saltlen + 16 + 1);
+    if (*encrypted == NULL) {
+        return NGX_ERROR;
+    }
+
+    p = ngx_cpymem(*encrypted, "$apr1$", sizeof("$apr1$") - 1);
+    p = ngx_copy(p, salt, saltlen);
+    *p++ = '$';
+
+    p = ngx_crypt_to64(p, (final[ 0]<<16) | (final[ 6]<<8) | final[12], 4);
+    p = ngx_crypt_to64(p, (final[ 1]<<16) | (final[ 7]<<8) | final[13], 4);
+    p = ngx_crypt_to64(p, (final[ 2]<<16) | (final[ 8]<<8) | final[14], 4);
+    p = ngx_crypt_to64(p, (final[ 3]<<16) | (final[ 9]<<8) | final[15], 4);
+    p = ngx_crypt_to64(p, (final[ 4]<<16) | (final[10]<<8) | final[ 5], 4);
+    p = ngx_crypt_to64(p, final[11], 2);
+    *p = '\0';
+
+    return NGX_OK;
+}
+
+
+static u_char *
+ngx_crypt_to64(u_char *p, uint32_t v, size_t n)
+{
+    static u_char   itoa64[] =
+        "./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
+
+    while (n--) {
+       *p++ = itoa64[v & 0x3f];
+       v >>= 6;
+    }
+
+    return p;
+}
+
+
+static ngx_int_t
+ngx_crypt_plain(ngx_pool_t *pool, u_char *key, u_char *salt, u_char **encrypted)
+{
+    size_t   len;
+    u_char  *p;
+
+    len = ngx_strlen(key);
+
+    *encrypted = ngx_pnalloc(pool, sizeof("{PLAIN}") - 1 + len + 1);
+    if (*encrypted == NULL) {
+        return NGX_ERROR;
+    }
+
+    p = ngx_cpymem(*encrypted, "{PLAIN}", sizeof("{PLAIN}") - 1);
+    ngx_memcpy(p, key, len + 1);
+
+    return NGX_OK;
+}
+
+
+#if (NGX_HAVE_SHA1)
+
+static ngx_int_t
+ngx_crypt_ssha(ngx_pool_t *pool, u_char *key, u_char *salt, u_char **encrypted)
+{
+    size_t       len;
+    ngx_str_t    encoded, decoded;
+    ngx_sha1_t   sha1;
+
+    /* "{SSHA}" base64(SHA1(key salt) salt) */
+
+    /* decode base64 salt to find out true salt */
+
+    encoded.data = salt + sizeof("{SSHA}") - 1;
+    encoded.len = ngx_strlen(encoded.data);
+
+    decoded.data = ngx_pnalloc(pool, ngx_base64_decoded_length(encoded.len));
+    if (decoded.data == NULL) {
+        return NGX_ERROR;
+    }
+
+    ngx_decode_base64(&decoded, &encoded);
+
+    /* update SHA1 from key and salt */
+
+    ngx_sha1_init(&sha1);
+    ngx_sha1_update(&sha1, key, ngx_strlen(key));
+    ngx_sha1_update(&sha1, decoded.data + 20, decoded.len - 20);
+    ngx_sha1_final(decoded.data, &sha1);
+
+    /* encode it back to base64 */
+
+    len = sizeof("{SSHA}") - 1 + ngx_base64_encoded_length(decoded.len) + 1;
+
+    *encrypted = ngx_pnalloc(pool, len);
+    if (*encrypted == NULL) {
+        return NGX_ERROR;
+    }
+
+    encoded.data = ngx_cpymem(*encrypted, "{SSHA}", sizeof("{SSHA}") - 1);
+    ngx_encode_base64(&encoded, &decoded);
+    encoded.data[encoded.len] = '\0';
+
+    return NGX_OK;
+}
+
+#endif /* NGX_HAVE_SHA1 */
diff --git a/src/core/ngx_crypt.h b/src/core/ngx_crypt.h
new file mode 100644 (file)
index 0000000..45ef81d
--- /dev/null
@@ -0,0 +1,19 @@
+
+/*
+ * Copyright (C) Igor Sysoev
+ */
+
+
+#ifndef _NGX_CRYPT_H_INCLUDED_
+#define _NGX_CRYPT_H_INCLUDED_
+
+
+#include <ngx_config.h>
+#include <ngx_core.h>
+
+
+ngx_int_t ngx_crypt(ngx_pool_t *pool, u_char *key, u_char *salt,
+    u_char **encrypted);
+
+
+#endif /* _NGX_CRYPT_H_INCLUDED_ */
index c6b7f92f195619ef4d520e1da3fb351273bc682a..45168de84045b4dc4d8327e4ef9a5b43bcb12962 100644 (file)
@@ -7,6 +7,7 @@
 #include <ngx_config.h>
 #include <ngx_core.h>
 #include <ngx_http.h>
+#include <ngx_crypt.h>
 
 
 #define NGX_HTTP_AUTH_BUF_SIZE  2048
index 165c6a46b9dc6bdd9f408c9a95fca066a063dec2..c46fb2bfd8d8f77c31226bc65358472e0b0cb1ab 100644 (file)
@@ -23,7 +23,7 @@
 #if (NGX_HAVE_GNU_CRYPT_R)
 
 ngx_int_t
-ngx_crypt(ngx_pool_t *pool, u_char *key, u_char *salt, u_char **encrypted)
+ngx_libc_crypt(ngx_pool_t *pool, u_char *key, u_char *salt, u_char **encrypted)
 {
     char               *value;
     size_t              len;
@@ -58,7 +58,7 @@ ngx_crypt(ngx_pool_t *pool, u_char *key, u_char *salt, u_char **encrypted)
 #else
 
 ngx_int_t
-ngx_crypt(ngx_pool_t *pool, u_char *key, u_char *salt, u_char **encrypted)
+ngx_libc_crypt(ngx_pool_t *pool, u_char *key, u_char *salt, u_char **encrypted)
 {
     char       *value;
     size_t      len;
index 7cd944d019e2a13301913bdf87ffe134c76d4728..68d1c6e5f0555b247695d0cc40b9eeeee03a6a58 100644 (file)
@@ -16,7 +16,7 @@ typedef uid_t  ngx_uid_t;
 typedef gid_t  ngx_gid_t;
 
 
-ngx_int_t ngx_crypt(ngx_pool_t *pool, u_char *key, u_char *salt,
+ngx_int_t ngx_libc_crypt(ngx_pool_t *pool, u_char *key, u_char *salt,
     u_char **encrypted);
 
 
index cc0760301aae8e22497c35026f5dae291f7e8d7a..5167870c03a59fcae109dba90cd7ea83649c1f68 100644 (file)
@@ -10,7 +10,7 @@
 #if (NGX_CRYPT)
 
 ngx_int_t
-ngx_crypt(ngx_pool_t *pool, u_char *key, u_char *salt, u_char **encrypted)
+ngx_libc_crypt(ngx_pool_t *pool, u_char *key, u_char *salt, u_char **encrypted)
 {
     /* STUB: a plain text password */
 
index 6e8c58bd22b18e1d34ad8ff4efd1f3a936d239ec..fd30df218df8a767c8b65cfea76baa978646adb0 100644 (file)
@@ -17,7 +17,7 @@
 #define ngx_gid_t  ngx_int_t
 
 
-ngx_int_t ngx_crypt(ngx_pool_t *pool, u_char *key, u_char *salt,
+ngx_int_t ngx_libc_crypt(ngx_pool_t *pool, u_char *key, u_char *salt,
     u_char **encrypted);