int main (int argc, char *argv[]) { size_t i; int rc; char out[BUFSIZ]; for (i = 0; i < sizeof (pkcs5) / sizeof (pkcs5[0]); i++) { rc = gc_pbkdf2_sha1 (pkcs5[i].password, strlen (pkcs5[i].password), pkcs5[i].salt, strlen (pkcs5[i].salt), pkcs5[i].iterations, out, pkcs5[i].dklen); if (rc != GC_OK) { printf ("PKCS5 entry %ld failed fatally: %d\n", (unsigned long) i, rc); return 1; } if (memcmp (pkcs5[i].expected, out, pkcs5[i].dklen) != 0) { printf ("PKCS5 entry %ld failed\n", (unsigned long) i); return 1; } } return 0; }
int _gsasl_scram_sha1_server_step (Gsasl_session * sctx, void *mech_data, const char *input, size_t input_len, char **output, size_t * output_len) { struct scram_server_state *state = mech_data; int res = GSASL_MECHANISM_CALLED_TOO_MANY_TIMES; int rc; *output = NULL; *output_len = 0; switch (state->step) { case 0: { if (input_len == 0) return GSASL_NEEDS_MORE; if (scram_parse_client_first (input, input_len, &state->cf) < 0) return GSASL_MECHANISM_PARSE_ERROR; /* In PLUS server mode, we require use of channel bindings. */ if (state->plus && state->cf.cbflag != 'p') return GSASL_AUTHENTICATION_ERROR; /* In non-PLUS mode, but where have channel bindings data (and thus advertised PLUS) we reject a client 'y' cbflag. */ if (!state->plus && state->cbtlsuniquelen > 0 && state->cf.cbflag == 'y') return GSASL_AUTHENTICATION_ERROR; /* Check that username doesn't fail SASLprep. */ { char *tmp; rc = gsasl_saslprep (state->cf.username, GSASL_ALLOW_UNASSIGNED, &tmp, NULL); if (rc != GSASL_OK || *tmp == '\0') return GSASL_AUTHENTICATION_ERROR; gsasl_free (tmp); } { const char *p; /* Save "gs2-header" and "message-bare" for next step. */ p = memchr (input, ',', input_len); if (!p) return GSASL_AUTHENTICATION_ERROR; p++; p = memchr (p, ',', input_len - (p - input)); if (!p) return GSASL_AUTHENTICATION_ERROR; p++; state->gs2header = malloc (p - input + 1); if (!state->gs2header) return GSASL_MALLOC_ERROR; memcpy (state->gs2header, input, p - input); state->gs2header[p - input] = '\0'; state->cfmb_str = malloc (input_len - (p - input) + 1); if (!state->cfmb_str) return GSASL_MALLOC_ERROR; memcpy (state->cfmb_str, p, input_len - (p - input)); state->cfmb_str[input_len - (p - input)] = '\0'; } /* Create new nonce. */ { size_t cnlen = strlen (state->cf.client_nonce); state->sf.nonce = malloc (cnlen + SNONCE_ENTROPY_BYTES + 1); if (!state->sf.nonce) return GSASL_MALLOC_ERROR; memcpy (state->sf.nonce, state->cf.client_nonce, cnlen); memcpy (state->sf.nonce + cnlen, state->snonce, SNONCE_ENTROPY_BYTES); state->sf.nonce[cnlen + SNONCE_ENTROPY_BYTES] = '\0'; } gsasl_property_set (sctx, GSASL_AUTHID, state->cf.username); gsasl_property_set (sctx, GSASL_AUTHZID, state->cf.authzid); { const char *p = gsasl_property_get (sctx, GSASL_SCRAM_ITER); if (p) state->sf.iter = strtoul (p, NULL, 10); if (!p || state->sf.iter == 0 || state->sf.iter == ULONG_MAX) state->sf.iter = 4096; } { const char *p = gsasl_property_get (sctx, GSASL_SCRAM_SALT); if (p) { free (state->sf.salt); state->sf.salt = strdup (p); } } rc = scram_print_server_first (&state->sf, &state->sf_str); if (rc != 0) return GSASL_MALLOC_ERROR; *output = strdup (state->sf_str); if (!*output) return GSASL_MALLOC_ERROR; *output_len = strlen (*output); state->step++; return GSASL_NEEDS_MORE; break; } case 1: { if (scram_parse_client_final (input, input_len, &state->cl) < 0) return GSASL_MECHANISM_PARSE_ERROR; if (strcmp (state->cl.nonce, state->sf.nonce) != 0) return GSASL_AUTHENTICATION_ERROR; /* Base64 decode the c= field and check that it matches client-first. Also check channel binding data. */ { size_t len; rc = gsasl_base64_from (state->cl.cbind, strlen (state->cl.cbind), &state->cbind, &len); if (rc != 0) return rc; if (state->cf.cbflag == 'p') { if (len < strlen (state->gs2header)) return GSASL_AUTHENTICATION_ERROR; if (memcmp (state->cbind, state->gs2header, strlen (state->gs2header)) != 0) return GSASL_AUTHENTICATION_ERROR; if (len - strlen (state->gs2header) != state->cbtlsuniquelen) return GSASL_AUTHENTICATION_ERROR; if (memcmp (state->cbind + strlen (state->gs2header), state->cbtlsunique, state->cbtlsuniquelen) != 0) return GSASL_AUTHENTICATION_ERROR; } else { if (len != strlen (state->gs2header)) return GSASL_AUTHENTICATION_ERROR; if (memcmp (state->cbind, state->gs2header, len) != 0) return GSASL_AUTHENTICATION_ERROR; } } /* Base64 decode client proof and check that length matches SHA-1 size. */ { size_t len; rc = gsasl_base64_from (state->cl.proof, strlen (state->cl.proof), &state->clientproof, &len); if (rc != 0) return rc; if (len != 20) return GSASL_MECHANISM_PARSE_ERROR; } { const char *p; /* Get StoredKey and ServerKey */ if ((p = gsasl_property_get (sctx, GSASL_PASSWORD))) { Gc_rc err; char *salt; size_t saltlen; char saltedpassword[20]; char *clientkey; char *preppasswd; rc = gsasl_saslprep (p, 0, &preppasswd, NULL); if (rc != GSASL_OK) return rc; rc = gsasl_base64_from (state->sf.salt, strlen (state->sf.salt), &salt, &saltlen); if (rc != 0) { gsasl_free (preppasswd); return rc; } /* SaltedPassword := Hi(password, salt) */ err = gc_pbkdf2_sha1 (preppasswd, strlen (preppasswd), salt, saltlen, state->sf.iter, saltedpassword, 20); gsasl_free (preppasswd); gsasl_free (salt); if (err != GC_OK) return GSASL_MALLOC_ERROR; /* ClientKey := HMAC(SaltedPassword, "Client Key") */ #define CLIENT_KEY "Client Key" rc = gsasl_hmac_sha1 (saltedpassword, 20, CLIENT_KEY, strlen (CLIENT_KEY), &clientkey); if (rc != 0) return rc; /* StoredKey := H(ClientKey) */ rc = gsasl_sha1 (clientkey, 20, &state->storedkey); free (clientkey); if (rc != 0) return rc; /* ServerKey := HMAC(SaltedPassword, "Server Key") */ #define SERVER_KEY "Server Key" rc = gsasl_hmac_sha1 (saltedpassword, 20, SERVER_KEY, strlen (SERVER_KEY), &state->serverkey); if (rc != 0) return rc; } else return GSASL_NO_PASSWORD; /* Compute AuthMessage */ { size_t len; int n; /* Get client-final-message-without-proof. */ p = memmem (input, input_len, ",p=", 3); if (!p) return GSASL_MECHANISM_PARSE_ERROR; len = p - input; n = asprintf (&state->authmessage, "%s,%.*s,%.*s", state->cfmb_str, (int) strlen (state->sf_str), state->sf_str, (int) len, input); if (n <= 0 || !state->authmessage) return GSASL_MALLOC_ERROR; } /* Check client proof. */ { char *clientsignature; char *maybe_storedkey; /* ClientSignature := HMAC(StoredKey, AuthMessage) */ rc = gsasl_hmac_sha1 (state->storedkey, 20, state->authmessage, strlen (state->authmessage), &clientsignature); if (rc != 0) return rc; /* ClientKey := ClientProof XOR ClientSignature */ memxor (clientsignature, state->clientproof, 20); rc = gsasl_sha1 (clientsignature, 20, &maybe_storedkey); free (clientsignature); if (rc != 0) return rc; rc = memcmp (state->storedkey, maybe_storedkey, 20); free (maybe_storedkey); if (rc != 0) return GSASL_AUTHENTICATION_ERROR; } /* Generate server verifier. */ { char *serversignature; /* ServerSignature := HMAC(ServerKey, AuthMessage) */ rc = gsasl_hmac_sha1 (state->serverkey, 20, state->authmessage, strlen (state->authmessage), &serversignature); if (rc != 0) return rc; rc = gsasl_base64_to (serversignature, 20, &state->sl.verifier, NULL); free (serversignature); if (rc != 0) return rc; } } rc = scram_print_server_final (&state->sl, output); if (rc != 0) return GSASL_MALLOC_ERROR; *output_len = strlen (*output); state->step++; return GSASL_OK; break; } default: break; } return res; }