|
17 | 17 | * by the SASLprep profile, we skip the SASLprep pre-processing and use
|
18 | 18 | * the raw bytes in calculating the hash.
|
19 | 19 | *
|
20 |
| - * - Channel binding is not supported yet. |
21 |
| - * |
22 | 20 | *
|
23 | 21 | * The password stored in pg_authid consists of the iteration count, salt,
|
24 | 22 | * StoredKey and ServerKey.
|
@@ -112,6 +110,11 @@ typedef struct
|
112 | 110 |
|
113 | 111 | constchar*username;/* username from startup packet */
|
114 | 112 |
|
| 113 | +boolssl_in_use; |
| 114 | +constchar*tls_finished_message; |
| 115 | +size_ttls_finished_len; |
| 116 | +char*channel_binding_type; |
| 117 | + |
115 | 118 | intiterations;
|
116 | 119 | char*salt;/* base64-encoded */
|
117 | 120 | uint8StoredKey[SCRAM_KEY_LEN];
|
@@ -168,14 +171,22 @@ static char *scram_mock_salt(const char *username);
|
168 | 171 | * it will fail, as if an incorrect password was given.
|
169 | 172 | */
|
170 | 173 | void*
|
171 |
| -pg_be_scram_init(constchar*username,constchar*shadow_pass) |
| 174 | +pg_be_scram_init(constchar*username, |
| 175 | +constchar*shadow_pass, |
| 176 | +boolssl_in_use, |
| 177 | +constchar*tls_finished_message, |
| 178 | +size_ttls_finished_len) |
172 | 179 | {
|
173 | 180 | scram_state*state;
|
174 | 181 | boolgot_verifier;
|
175 | 182 |
|
176 | 183 | state= (scram_state*)palloc0(sizeof(scram_state));
|
177 | 184 | state->state=SCRAM_AUTH_INIT;
|
178 | 185 | state->username=username;
|
| 186 | +state->ssl_in_use=ssl_in_use; |
| 187 | +state->tls_finished_message=tls_finished_message; |
| 188 | +state->tls_finished_len=tls_finished_len; |
| 189 | +state->channel_binding_type=NULL; |
179 | 190 |
|
180 | 191 | /*
|
181 | 192 | * Parse the stored password verifier.
|
@@ -773,45 +784,96 @@ read_client_first_message(scram_state *state, char *input)
|
773 | 784 | *------
|
774 | 785 | */
|
775 | 786 |
|
776 |
| -/* read gs2-cbind-flag */ |
| 787 | +/* |
| 788 | + * Read gs2-cbind-flag. (For details see also RFC 5802 Section 6 "Channel |
| 789 | + * Binding".) |
| 790 | + */ |
777 | 791 | switch (*input)
|
778 | 792 | {
|
779 | 793 | case'n':
|
780 |
| -/* Client does not support channel binding */ |
| 794 | +/* |
| 795 | + * The client does not support channel binding or has simply |
| 796 | + * decided to not use it. In that case just let it go. |
| 797 | + */ |
| 798 | +input++; |
| 799 | +if (*input!=',') |
| 800 | +ereport(ERROR, |
| 801 | +(errcode(ERRCODE_PROTOCOL_VIOLATION), |
| 802 | +errmsg("malformed SCRAM message"), |
| 803 | +errdetail("Comma expected, but found character \"%s\".", |
| 804 | +sanitize_char(*input)))); |
781 | 805 | input++;
|
782 | 806 | break;
|
783 | 807 | case'y':
|
784 |
| -/* Client supports channel binding, but we're not doing it today */ |
| 808 | +/* |
| 809 | + * The client supports channel binding and thinks that the server |
| 810 | + * does not. In this case, the server must fail authentication if |
| 811 | + * it supports channel binding, which in this implementation is |
| 812 | + * the case if a connection is using SSL. |
| 813 | + */ |
| 814 | +if (state->ssl_in_use) |
| 815 | +ereport(ERROR, |
| 816 | +(errcode(ERRCODE_INVALID_AUTHORIZATION_SPECIFICATION), |
| 817 | +errmsg("SCRAM channel binding negotiation error"), |
| 818 | +errdetail("The client supports SCRAM channel binding but thinks the server does not. " |
| 819 | +"However, this server does support channel binding."))); |
| 820 | +input++; |
| 821 | +if (*input!=',') |
| 822 | +ereport(ERROR, |
| 823 | +(errcode(ERRCODE_PROTOCOL_VIOLATION), |
| 824 | +errmsg("malformed SCRAM message"), |
| 825 | +errdetail("Comma expected, but found character \"%s\".", |
| 826 | +sanitize_char(*input)))); |
785 | 827 | input++;
|
786 | 828 | break;
|
787 | 829 | case'p':
|
788 |
| - |
789 | 830 | /*
|
790 |
| - * Client requires channel binding. We don't support it. |
791 |
| - * |
792 |
| - * RFC 5802 specifies a particular error code, |
793 |
| - * e=server-does-support-channel-binding, for this. But it can |
794 |
| - * only be sent in the server-final message, and we don't want to |
795 |
| - * go through the motions of the authentication, knowing it will |
796 |
| - * fail, just to send that error message. |
| 831 | + * The client requires channel binding. Channel binding type |
| 832 | + * follows, e.g., "p=tls-unique". |
797 | 833 | */
|
798 |
| -ereport(ERROR, |
799 |
| -(errcode(ERRCODE_FEATURE_NOT_SUPPORTED), |
800 |
| -errmsg("client requires SCRAM channel binding, but it is not supported"))); |
| 834 | +{ |
| 835 | +char*channel_binding_type; |
| 836 | + |
| 837 | +if (!state->ssl_in_use) |
| 838 | +{ |
| 839 | +/* |
| 840 | + * Without SSL, we don't support channel binding. |
| 841 | + * |
| 842 | + * RFC 5802 specifies a particular error code, |
| 843 | + * e=server-does-support-channel-binding, for this. But |
| 844 | + * it can only be sent in the server-final message, and we |
| 845 | + * don't want to go through the motions of the |
| 846 | + * authentication, knowing it will fail, just to send that |
| 847 | + * error message. |
| 848 | + */ |
| 849 | +ereport(ERROR, |
| 850 | +(errcode(ERRCODE_PROTOCOL_VIOLATION), |
| 851 | +errmsg("client requires SCRAM channel binding, but it is not supported"))); |
| 852 | +} |
| 853 | + |
| 854 | +/* |
| 855 | + * Read value provided by client; only tls-unique is supported |
| 856 | + * for now. (It is not safe to print the name of an |
| 857 | + * unsupported binding type in the error message. Pranksters |
| 858 | + * could print arbitrary strings into the log that way.) |
| 859 | + */ |
| 860 | +channel_binding_type=read_attr_value(&input,'p'); |
| 861 | +if (strcmp(channel_binding_type,SCRAM_CHANNEL_BINDING_TLS_UNIQUE)!=0) |
| 862 | +ereport(ERROR, |
| 863 | +(errcode(ERRCODE_PROTOCOL_VIOLATION), |
| 864 | + (errmsg("unsupported SCRAM channel-binding type")))); |
| 865 | + |
| 866 | +/* Save the name for handling of subsequent messages */ |
| 867 | +state->channel_binding_type=pstrdup(channel_binding_type); |
| 868 | +} |
| 869 | +break; |
801 | 870 | default:
|
802 | 871 | ereport(ERROR,
|
803 | 872 | (errcode(ERRCODE_PROTOCOL_VIOLATION),
|
804 | 873 | errmsg("malformed SCRAM message"),
|
805 | 874 | errdetail("Unexpected channel-binding flag \"%s\".",
|
806 | 875 | sanitize_char(*input))));
|
807 | 876 | }
|
808 |
| -if (*input!=',') |
809 |
| -ereport(ERROR, |
810 |
| -(errcode(ERRCODE_PROTOCOL_VIOLATION), |
811 |
| -errmsg("malformed SCRAM message"), |
812 |
| -errdetail("Comma expected, but found character \"%s\".", |
813 |
| -sanitize_char(*input)))); |
814 |
| -input++; |
815 | 877 |
|
816 | 878 | /*
|
817 | 879 | * Forbid optional authzid (authorization identity). We don't support it.
|
@@ -1032,14 +1094,73 @@ read_client_final_message(scram_state *state, char *input)
|
1032 | 1094 | */
|
1033 | 1095 |
|
1034 | 1096 | /*
|
1035 |
| - * Read channel-binding.We don't support channelbinding, so it's |
1036 |
| - *expected to always be "biws", which is "n,,", base64-encoded. |
| 1097 | + * Read channelbinding.This repeats the channel-binding flags and is |
| 1098 | + *then followed by the actual binding data depending on the type. |
1037 | 1099 | */
|
1038 | 1100 | channel_binding=read_attr_value(&p,'c');
|
1039 |
| -if (strcmp(channel_binding,"biws")!=0) |
1040 |
| -ereport(ERROR, |
1041 |
| -(errcode(ERRCODE_PROTOCOL_VIOLATION), |
1042 |
| - (errmsg("unexpected SCRAM channel-binding attribute in client-final-message")))); |
| 1101 | +if (state->channel_binding_type) |
| 1102 | +{ |
| 1103 | +constchar*cbind_data=NULL; |
| 1104 | +size_tcbind_data_len=0; |
| 1105 | +size_tcbind_header_len; |
| 1106 | +char*cbind_input; |
| 1107 | +size_tcbind_input_len; |
| 1108 | +char*b64_message; |
| 1109 | +intb64_message_len; |
| 1110 | + |
| 1111 | +/* |
| 1112 | + * Fetch data appropriate for channel binding type |
| 1113 | + */ |
| 1114 | +if (strcmp(state->channel_binding_type,SCRAM_CHANNEL_BINDING_TLS_UNIQUE)==0) |
| 1115 | +{ |
| 1116 | +cbind_data=state->tls_finished_message; |
| 1117 | +cbind_data_len=state->tls_finished_len; |
| 1118 | +} |
| 1119 | +else |
| 1120 | +{ |
| 1121 | +/* should not happen */ |
| 1122 | +elog(ERROR,"invalid channel binding type"); |
| 1123 | +} |
| 1124 | + |
| 1125 | +/* should not happen */ |
| 1126 | +if (cbind_data==NULL||cbind_data_len==0) |
| 1127 | +elog(ERROR,"empty channel binding data for channel binding type \"%s\"", |
| 1128 | +state->channel_binding_type); |
| 1129 | + |
| 1130 | +cbind_header_len=4+strlen(state->channel_binding_type);/* p=type,, */ |
| 1131 | +cbind_input_len=cbind_header_len+cbind_data_len; |
| 1132 | +cbind_input=palloc(cbind_input_len); |
| 1133 | +snprintf(cbind_input,cbind_input_len,"p=%s,,",state->channel_binding_type); |
| 1134 | +memcpy(cbind_input+cbind_header_len,cbind_data,cbind_data_len); |
| 1135 | + |
| 1136 | +b64_message=palloc(pg_b64_enc_len(cbind_input_len)+1); |
| 1137 | +b64_message_len=pg_b64_encode(cbind_input,cbind_input_len, |
| 1138 | +b64_message); |
| 1139 | +b64_message[b64_message_len]='\0'; |
| 1140 | + |
| 1141 | +/* |
| 1142 | + * Compare the value sent by the client with the value expected by |
| 1143 | + * the server. |
| 1144 | + */ |
| 1145 | +if (strcmp(channel_binding,b64_message)!=0) |
| 1146 | +ereport(ERROR, |
| 1147 | +(errcode(ERRCODE_INVALID_AUTHORIZATION_SPECIFICATION), |
| 1148 | + (errmsg("SCRAM channel binding check failed")))); |
| 1149 | +} |
| 1150 | +else |
| 1151 | +{ |
| 1152 | +/* |
| 1153 | + * If we are not using channel binding, the binding data is expected |
| 1154 | + * to always be "biws", which is "n,," base64-encoded, or "eSws", |
| 1155 | + * which is "y,,". |
| 1156 | + */ |
| 1157 | +if (strcmp(channel_binding,"biws")!=0&& |
| 1158 | +strcmp(channel_binding,"eSws")!=0) |
| 1159 | +ereport(ERROR, |
| 1160 | +(errcode(ERRCODE_PROTOCOL_VIOLATION), |
| 1161 | + (errmsg("unexpected SCRAM channel-binding attribute in client-final-message")))); |
| 1162 | +} |
| 1163 | + |
1043 | 1164 | state->client_final_nonce=read_attr_value(&p,'r');
|
1044 | 1165 |
|
1045 | 1166 | /* ignore optional extensions */
|
|