]> granicus.if.org Git - apache/commitdiff
Add support for SHA-2 crypt() algorithm in htpasswd.
authorJoe Orton <jorton@apache.org>
Fri, 21 Jun 2019 16:20:29 +0000 (16:20 +0000)
committerJoe Orton <jorton@apache.org>
Fri, 21 Jun 2019 16:20:29 +0000 (16:20 +0000)
* configure.in: Detect SHA-2 support in crypt().

* support/passwd_common.h: Define ALG_CRYPT_SHA256, ALG_CRYPT_SHA512,
  include ap_config_auto.h.

* support/htpasswd.c (check_args): Allow -2, -5, -r arguments for
  SHA-256, SHA-256 and rounds options respectively.

* support/passwd_common.c
  (parse_common_options): Parse -2, -5, -r args.
  (mkhash): Generate crypt hash for SHA256/SHA512 algorithms.

git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/trunk@1861793 13f79535-47bb-0310-9956-ffa450edef68

configure.in
support/htpasswd.c
support/passwd_common.c
support/passwd_common.h

index 6c8a6d4886f4cd2a099a0cc89c432131e5f95154..6199f6daf7189ad92b8df76f432865d33e3672cd 100644 (file)
@@ -500,6 +500,28 @@ LIBS=""
 AC_SEARCH_LIBS(crypt, crypt)
 CRYPT_LIBS="$LIBS"
 APACHE_SUBST(CRYPT_LIBS)
+
+if test "$ac_cv_search_crypt" != "no"; then
+   # Test crypt() with the SHA-512 test vector from https://akkadia.org/drepper/SHA-crypt.txt
+   AC_CACHE_CHECK([whether crypt() supports SHA-2], [ap_cv_crypt_sha2], [
+    AC_RUN_IFELSE([AC_LANG_PROGRAM([[
+#include <crypt.h>
+#include <stdlib.h>
+#include <string.h>
+
+#define PASSWD_0 "Hello world!"
+#define SALT_0 "\$6\$saltstring"
+#define EXPECT_0 "\$6\$saltstring\$svn8UoSVapNtMuq1ukKS4tPQd8iKwSMHWjl/O817G3uBnIFNjnQJu" \
+               "esI68u4OTLiBFdcbYEdFCoEOfaS35inz1"
+]], [char *result = crypt(PASSWD_0, SALT_0);
+     if (!result) return 1;
+     if (strcmp(result, EXPECT_0)) return 2;
+])], [ap_cv_crypt_sha2=yes], [ap_cv_crypt_sha2=no])])
+   if test "$ap_cv_crypt_sha2" = yes; then
+     AC_DEFINE([HAVE_CRYPT_SHA2], 1, [Define if crypt() supports SHA-2 hashes])
+   fi
+fi
+
 LIBS="$saved_LIBS"
 
 dnl See Comment #Spoon
index 73b291d72c178b1e10ea2726eb19a5aae4e79a68..f399a9b423bf09d118702746904b264155bc617f 100644 (file)
@@ -178,7 +178,7 @@ static void check_args(int argc, const char *const argv[],
     if (rv != APR_SUCCESS)
         exit(ERR_SYNTAX);
 
-    while ((rv = apr_getopt(state, "cnmspdBbDiC:v", &opt, &opt_arg)) == APR_SUCCESS) {
+    while ((rv = apr_getopt(state, "cnmspdBbDi25C:r:v", &opt, &opt_arg)) == APR_SUCCESS) {
         switch (opt) {
         case 'c':
             *mask |= APHTP_NEWFILE;
index 664e509b9568ca6cdabff5ada74286239c3201f6..d45657cc262b5c0b559c22255efba63d1d124cee 100644 (file)
@@ -185,10 +185,15 @@ int mkhash(struct passwd_ctx *ctx)
 #if CRYPT_ALGO_SUPPORTED
     char *cbuf;
 #endif
+#ifdef HAVE_CRYPT_SHA2
+    const char *setting;
+    char method;
+#endif
 
-    if (ctx->cost != 0 && ctx->alg != ALG_BCRYPT) {
+    if (ctx->cost != 0 && ctx->alg != ALG_BCRYPT
+        && ctx->alg != ALG_CRYPT_SHA256 && ctx->alg != ALG_CRYPT_SHA512 ) {
         apr_file_printf(errfile,
-                        "Warning: Ignoring -C argument for this algorithm." NL);
+                        "Warning: Ignoring -C/-r argument for this algorithm." NL);
     }
 
     if (ctx->passwd == NULL) {
@@ -246,6 +251,34 @@ int mkhash(struct passwd_ctx *ctx)
         break;
 #endif /* CRYPT_ALGO_SUPPORTED */
 
+#ifdef HAVE_CRYPT_SHA2
+    case ALG_CRYPT_SHA256:
+    case ALG_CRYPT_SHA512:
+        ret = generate_salt(salt, 16, &ctx->errstr, ctx->pool);
+        if (ret != 0)
+            break;
+
+        method = ctx->alg == ALG_CRYPT_SHA256 ? '5': '6';
+
+        if (ctx->cost) 
+            setting = apr_psprintf(ctx->pool, "$%c$rounds=%d$%s",
+                                   method, ctx->cost, salt);
+        else
+            setting = apr_psprintf(ctx->pool, "$%c$%s",
+                                   method, salt);
+
+        cbuf = crypt(pw, setting);
+        if (cbuf == NULL) {
+            rv = APR_FROM_OS_ERROR(errno);
+            ctx->errstr = apr_psprintf(ctx->pool, "crypt() failed: %pm", &rv);
+            ret = ERR_PWMISMATCH;
+            break;
+        }
+
+        apr_cpystrn(ctx->out, cbuf, ctx->out_len - 1);
+        break;
+#endif /* HAVE_CRYPT_SHA2 */
+
 #if BCRYPT_ALGO_SUPPORTED
     case ALG_BCRYPT:
         rv = apr_generate_random_bytes((unsigned char*)salt, 16);
@@ -294,6 +327,19 @@ int parse_common_options(struct passwd_ctx *ctx, char opt,
     case 's':
         ctx->alg = ALG_APSHA;
         break;
+#ifdef HAVE_CRYPT_SHA2
+    case '2':
+        ctx->alg = ALG_CRYPT_SHA256;
+        break;
+    case '5':
+        ctx->alg = ALG_CRYPT_SHA512;
+        break;
+#else
+    case '2':
+    case '5':
+        ctx->errstr = "SHA-2 crypt() algorithms are not supported on this platform.";
+        return ERR_ALG_NOT_SUPP;
+#endif
     case 'p':
         ctx->alg = ALG_PLAIN;
 #if !PLAIN_ALGO_SUPPORTED
@@ -324,11 +370,12 @@ int parse_common_options(struct passwd_ctx *ctx, char opt,
         return ERR_ALG_NOT_SUPP;
 #endif
         break;
-    case 'C': {
+    case 'C':
+    case 'r': {
             char *endptr;
             long num = strtol(opt_arg, &endptr, 10);
             if (*endptr != '\0' || num <= 0) {
-                ctx->errstr = "argument to -C must be a positive integer";
+                ctx->errstr = "argument to -C/-r must be a positive integer";
                 return ERR_SYNTAX;
             }
             ctx->cost = num;
index 660081e9084935ef3c79ca565db7ff021ec72053..f1b3cd7ec639b81caa59724b7678bf4e6d8dffee 100644 (file)
@@ -28,6 +28,8 @@
 #include "apu_version.h"
 #endif
 
+#include "ap_config_auto.h"
+
 #define MAX_STRING_LEN 256
 
 #define ALG_PLAIN 0
@@ -35,6 +37,8 @@
 #define ALG_APMD5 2
 #define ALG_APSHA 3
 #define ALG_BCRYPT 4
+#define ALG_CRYPT_SHA256 5
+#define ALG_CRYPT_SHA512 6
 
 #define BCRYPT_DEFAULT_COST 5
 
@@ -84,7 +88,7 @@ struct passwd_ctx {
     apr_size_t      out_len;
     char            *passwd;
     int             alg;
-    int             cost;
+    int             cost; /* cost for bcrypt, rounds for SHA-2 */
     enum {
         PW_PROMPT = 0,
         PW_ARG,