}
return str_c(out);
}
+
+static bool
+parse_scram_client_first(struct scram_auth_request *request,
+ const unsigned char *data, size_t size,
+ const char **error_r)
+{
+ const char *login_username = NULL;
+ const char *data_cstr, *p;
+ const char *gs2_header, *gs2_cbind_flag, *authzid;
+ const char *cfm_bare, *username, *nonce;
+ const char *const *fields;
+
+ data_cstr = gs2_header = t_strndup(data, size);
+
+ /* RFC 5802, Section 7:
+
+ client-first-message = gs2-header client-first-message-bare
+ gs2-header = gs2-cbind-flag "," [ authzid ] ","
+
+ client-first-message-bare = [reserved-mext ","]
+ username "," nonce ["," extensions]
+
+ extensions = attr-val *("," attr-val)
+ ;; All extensions are optional,
+ ;; i.e., unrecognized attributes
+ ;; not defined in this document
+ ;; MUST be ignored.
+ attr-val = ALPHA "=" value
+ */
+ p = strchr(data_cstr, ',');
+ if (p == NULL) {
+ *error_r = "Invalid initial client message: "
+ "Missing first ',' in GS2 header";
+ return FALSE;
+ }
+ gs2_cbind_flag = t_strdup_until(data_cstr, p);
+ data_cstr = p + 1;
+
+ p = strchr(data_cstr, ',');
+ if (p == NULL) {
+ *error_r = "Invalid initial client message: "
+ "Missing second ',' in GS2 header";
+ return FALSE;
+ }
+ authzid = t_strdup_until(data_cstr, p);
+ gs2_header = t_strdup_until(gs2_header, p + 1);
+ cfm_bare = p + 1;
+
+ fields = t_strsplit(cfm_bare, ",");
+ if (str_array_length(fields) < 2) {
+ *error_r = "Invalid initial client message: "
+ "Missing nonce field";
+ return FALSE;
+ }
+ username = fields[0];
+ nonce = fields[1];
+
+ /* gs2-cbind-flag = ("p=" cb-name) / "n" / "y"
+ */
+ switch (gs2_cbind_flag[0]) {
+ case 'p':
+ *error_r = "Channel binding not supported";
+ return FALSE;
+ case 'y':
+ case 'n':
+ break;
+ default:
+ *error_r = "Invalid GS2 header";
+ return FALSE;
+ }
+
+ /* authzid = "a=" saslname
+ ;; Protocol specific.
+ */
+ if (authzid[0] == '\0')
+ ;
+ else if (authzid[0] == 'a' && authzid[1] == '=') {
+ /* Unescape authzid */
+ login_username = scram_unescape_username(authzid + 2);
+
+ if (login_username == NULL) {
+ *error_r = "authzid escaping is invalid";
+ return FALSE;
+ }
+ } else {
+ *error_r = "Invalid authzid field";
+ return FALSE;
+ }
+
+ /* reserved-mext = "m=" 1*(value-char)
+ */
+ if (username[0] == 'm') {
+ *error_r = "Mandatory extension(s) not supported";
+ return FALSE;
+ }
+ /* username = "n=" saslname
+ */
+ if (username[0] == 'n' && username[1] == '=') {
+ /* Unescape username */
+ username = scram_unescape_username(username + 2);
+ if (username == NULL) {
+ *error_r = "Username escaping is invalid";
+ return FALSE;
+ }
+ if (!auth_request_set_username(&request->auth_request,
+ username, error_r))
+ return FALSE;
+ } else {
+ *error_r = "Invalid username field";
+ return FALSE;
+ }
+ if (login_username != NULL) {
+ if (!auth_request_set_login_username(&request->auth_request,
+ login_username, error_r))
+ return FALSE;
+ }
+
+ /* nonce = "r=" c-nonce [s-nonce] */
+ if (nonce[0] == 'r' && nonce[1] == '=')
+ request->cnonce = p_strdup(request->pool, nonce+2);
+ else {
+ *error_r = "Invalid client nonce";
+ return FALSE;
+ }
+
+ request->gs2_header = p_strdup(request->pool, gs2_header);
+ request->client_first_message_bare = p_strdup(request->pool, cfm_bare);
+ return TRUE;
+}
#include "auth-scram-server.c"
-static bool
-parse_scram_client_first(struct scram_auth_request *request,
- const unsigned char *data, size_t size,
- const char **error_r)
-{
- const char *login_username = NULL;
- const char *data_cstr, *p;
- const char *gs2_header, *gs2_cbind_flag, *authzid;
- const char *cfm_bare, *username, *nonce;
- const char *const *fields;
-
- data_cstr = gs2_header = t_strndup(data, size);
-
- /* RFC 5802, Section 7:
-
- client-first-message = gs2-header client-first-message-bare
- gs2-header = gs2-cbind-flag "," [ authzid ] ","
-
- client-first-message-bare = [reserved-mext ","]
- username "," nonce ["," extensions]
-
- extensions = attr-val *("," attr-val)
- ;; All extensions are optional,
- ;; i.e., unrecognized attributes
- ;; not defined in this document
- ;; MUST be ignored.
- attr-val = ALPHA "=" value
- */
- p = strchr(data_cstr, ',');
- if (p == NULL) {
- *error_r = "Invalid initial client message: "
- "Missing first ',' in GS2 header";
- return FALSE;
- }
- gs2_cbind_flag = t_strdup_until(data_cstr, p);
- data_cstr = p + 1;
-
- p = strchr(data_cstr, ',');
- if (p == NULL) {
- *error_r = "Invalid initial client message: "
- "Missing second ',' in GS2 header";
- return FALSE;
- }
- authzid = t_strdup_until(data_cstr, p);
- gs2_header = t_strdup_until(gs2_header, p + 1);
- cfm_bare = p + 1;
-
- fields = t_strsplit(cfm_bare, ",");
- if (str_array_length(fields) < 2) {
- *error_r = "Invalid initial client message: "
- "Missing nonce field";
- return FALSE;
- }
- username = fields[0];
- nonce = fields[1];
-
- /* gs2-cbind-flag = ("p=" cb-name) / "n" / "y"
- */
- switch (gs2_cbind_flag[0]) {
- case 'p':
- *error_r = "Channel binding not supported";
- return FALSE;
- case 'y':
- case 'n':
- break;
- default:
- *error_r = "Invalid GS2 header";
- return FALSE;
- }
-
- /* authzid = "a=" saslname
- ;; Protocol specific.
- */
- if (authzid[0] == '\0')
- ;
- else if (authzid[0] == 'a' && authzid[1] == '=') {
- /* Unescape authzid */
- login_username = scram_unescape_username(authzid + 2);
-
- if (login_username == NULL) {
- *error_r = "authzid escaping is invalid";
- return FALSE;
- }
- } else {
- *error_r = "Invalid authzid field";
- return FALSE;
- }
-
- /* reserved-mext = "m=" 1*(value-char)
- */
- if (username[0] == 'm') {
- *error_r = "Mandatory extension(s) not supported";
- return FALSE;
- }
- /* username = "n=" saslname
- */
- if (username[0] == 'n' && username[1] == '=') {
- /* Unescape username */
- username = scram_unescape_username(username + 2);
- if (username == NULL) {
- *error_r = "Username escaping is invalid";
- return FALSE;
- }
- if (!auth_request_set_username(&request->auth_request,
- username, error_r))
- return FALSE;
- } else {
- *error_r = "Invalid username field";
- return FALSE;
- }
- if (login_username != NULL) {
- if (!auth_request_set_login_username(&request->auth_request,
- login_username, error_r))
- return FALSE;
- }
-
- /* nonce = "r=" c-nonce [s-nonce] */
- if (nonce[0] == 'r' && nonce[1] == '=')
- request->cnonce = p_strdup(request->pool, nonce+2);
- else {
- *error_r = "Invalid client nonce";
- return FALSE;
- }
-
- request->gs2_header = p_strdup(request->pool, gs2_header);
- request->client_first_message_bare = p_strdup(request->pool, cfm_bare);
- return TRUE;
-}
-
static bool verify_credentials(struct scram_auth_request *request)
{
const struct hash_method *hmethod = request->hash_method;