Mercurial > dropbear
comparison svr-authpubkey.c @ 1733:d529a52b2f7c coverity coverity
merge coverity from main
author | Matt Johnston <matt@ucc.asn.au> |
---|---|
date | Fri, 26 Jun 2020 21:07:34 +0800 |
parents | ae41624c2198 |
children | 064f5be2fc45 |
comparison
equal
deleted
inserted
replaced
1643:b59623a64678 | 1733:d529a52b2f7c |
---|---|
68 #if DROPBEAR_SVR_PUBKEY_AUTH | 68 #if DROPBEAR_SVR_PUBKEY_AUTH |
69 | 69 |
70 #define MIN_AUTHKEYS_LINE 10 /* "ssh-rsa AB" - short but doesn't matter */ | 70 #define MIN_AUTHKEYS_LINE 10 /* "ssh-rsa AB" - short but doesn't matter */ |
71 #define MAX_AUTHKEYS_LINE 4200 /* max length of a line in authkeys */ | 71 #define MAX_AUTHKEYS_LINE 4200 /* max length of a line in authkeys */ |
72 | 72 |
73 static int checkpubkey(const char* algo, unsigned int algolen, | 73 static int checkpubkey(const char* keyalgo, unsigned int keyalgolen, |
74 const unsigned char* keyblob, unsigned int keybloblen); | 74 const unsigned char* keyblob, unsigned int keybloblen); |
75 static int checkpubkeyperms(void); | 75 static int checkpubkeyperms(void); |
76 static void send_msg_userauth_pk_ok(const char* algo, unsigned int algolen, | 76 static void send_msg_userauth_pk_ok(const char* sigalgo, unsigned int sigalgolen, |
77 const unsigned char* keyblob, unsigned int keybloblen); | 77 const unsigned char* keyblob, unsigned int keybloblen); |
78 static int checkfileperm(char * filename); | 78 static int checkfileperm(char * filename); |
79 | 79 |
80 /* process a pubkey auth request, sending success or failure message as | 80 /* process a pubkey auth request, sending success or failure message as |
81 * appropriate */ | 81 * appropriate */ |
82 void svr_auth_pubkey(int valid_user) { | 82 void svr_auth_pubkey(int valid_user) { |
83 | 83 |
84 unsigned char testkey; /* whether we're just checking if a key is usable */ | 84 unsigned char testkey; /* whether we're just checking if a key is usable */ |
85 char* algo = NULL; /* pubkey algo */ | 85 char* sigalgo = NULL; |
86 unsigned int algolen; | 86 unsigned int sigalgolen; |
87 const char* keyalgo; | |
88 unsigned int keyalgolen; | |
87 unsigned char* keyblob = NULL; | 89 unsigned char* keyblob = NULL; |
88 unsigned int keybloblen; | 90 unsigned int keybloblen; |
89 unsigned int sign_payload_length; | 91 unsigned int sign_payload_length; |
90 buffer * signbuf = NULL; | 92 buffer * signbuf = NULL; |
91 sign_key * key = NULL; | 93 sign_key * key = NULL; |
92 char* fp = NULL; | 94 char* fp = NULL; |
93 enum signkey_type type = -1; | 95 enum signature_type sigtype; |
96 enum signkey_type keytype; | |
97 int auth_failure = 1; | |
94 | 98 |
95 TRACE(("enter pubkeyauth")) | 99 TRACE(("enter pubkeyauth")) |
96 | 100 |
97 /* 0 indicates user just wants to check if key can be used, 1 is an | 101 /* 0 indicates user just wants to check if key can be used, 1 is an |
98 * actual attempt*/ | 102 * actual attempt*/ |
99 testkey = (buf_getbool(ses.payload) == 0); | 103 testkey = (buf_getbool(ses.payload) == 0); |
100 | 104 |
101 algo = buf_getstring(ses.payload, &algolen); | 105 sigalgo = buf_getstring(ses.payload, &sigalgolen); |
102 keybloblen = buf_getint(ses.payload); | 106 keybloblen = buf_getint(ses.payload); |
103 keyblob = buf_getptr(ses.payload, keybloblen); | 107 keyblob = buf_getptr(ses.payload, keybloblen); |
104 | 108 |
105 if (!valid_user) { | 109 if (!valid_user) { |
106 /* Return failure once we have read the contents of the packet | 110 /* Return failure once we have read the contents of the packet |
109 testing for user existence if the public key is known */ | 113 testing for user existence if the public key is known */ |
110 send_msg_userauth_failure(0, 0); | 114 send_msg_userauth_failure(0, 0); |
111 goto out; | 115 goto out; |
112 } | 116 } |
113 | 117 |
118 sigtype = signature_type_from_name(sigalgo, sigalgolen); | |
119 if (sigtype == DROPBEAR_SIGNATURE_NONE) { | |
120 send_msg_userauth_failure(0, 0); | |
121 goto out; | |
122 } | |
123 | |
124 keytype = signkey_type_from_signature(sigtype); | |
125 keyalgo = signkey_name_from_type(keytype, &keyalgolen); | |
126 | |
127 #if DROPBEAR_PLUGIN | |
128 if (svr_ses.plugin_instance != NULL) { | |
129 char *options_buf; | |
130 if (svr_ses.plugin_instance->checkpubkey( | |
131 svr_ses.plugin_instance, | |
132 &ses.plugin_session, | |
133 keyalgo, | |
134 keyalgolen, | |
135 keyblob, | |
136 keybloblen, | |
137 ses.authstate.username) == DROPBEAR_SUCCESS) { | |
138 /* Success */ | |
139 auth_failure = 0; | |
140 | |
141 /* Options provided? */ | |
142 options_buf = ses.plugin_session->get_options(ses.plugin_session); | |
143 if (options_buf) { | |
144 struct buf temp_buf = { | |
145 .data = (unsigned char *)options_buf, | |
146 .len = strlen(options_buf), | |
147 .pos = 0, | |
148 .size = 0 | |
149 }; | |
150 int ret = svr_add_pubkey_options(&temp_buf, 0, "N/A"); | |
151 if (ret == DROPBEAR_FAILURE) { | |
152 /* Fail immediately as the plugin provided wrong options */ | |
153 send_msg_userauth_failure(0, 0); | |
154 goto out; | |
155 } | |
156 } | |
157 } | |
158 } | |
159 #endif | |
114 /* check if the key is valid */ | 160 /* check if the key is valid */ |
115 if (checkpubkey(algo, algolen, keyblob, keybloblen) == DROPBEAR_FAILURE) { | 161 if (auth_failure) { |
162 auth_failure = checkpubkey(keyalgo, keyalgolen, keyblob, keybloblen) == DROPBEAR_FAILURE; | |
163 } | |
164 | |
165 if (auth_failure) { | |
116 send_msg_userauth_failure(0, 0); | 166 send_msg_userauth_failure(0, 0); |
117 goto out; | 167 goto out; |
118 } | 168 } |
119 | 169 |
120 /* let them know that the key is ok to use */ | 170 /* let them know that the key is ok to use */ |
121 if (testkey) { | 171 if (testkey) { |
122 send_msg_userauth_pk_ok(algo, algolen, keyblob, keybloblen); | 172 send_msg_userauth_pk_ok(sigalgo, sigalgolen, keyblob, keybloblen); |
123 goto out; | 173 goto out; |
124 } | 174 } |
125 | 175 |
126 /* now we can actually verify the signature */ | 176 /* now we can actually verify the signature */ |
127 | 177 |
128 /* get the key */ | 178 /* get the key */ |
129 key = new_sign_key(); | 179 key = new_sign_key(); |
130 type = DROPBEAR_SIGNKEY_ANY; | 180 if (buf_get_pub_key(ses.payload, key, &keytype) == DROPBEAR_FAILURE) { |
131 if (buf_get_pub_key(ses.payload, key, &type) == DROPBEAR_FAILURE) { | |
132 send_msg_userauth_failure(0, 1); | 181 send_msg_userauth_failure(0, 1); |
133 goto out; | 182 goto out; |
134 } | 183 } |
135 | 184 |
136 /* create the data which has been signed - this a string containing | 185 /* create the data which has been signed - this a string containing |
149 | 198 |
150 buf_setpos(signbuf, 0); | 199 buf_setpos(signbuf, 0); |
151 | 200 |
152 /* ... and finally verify the signature */ | 201 /* ... and finally verify the signature */ |
153 fp = sign_key_fingerprint(keyblob, keybloblen); | 202 fp = sign_key_fingerprint(keyblob, keybloblen); |
154 if (buf_verify(ses.payload, key, signbuf) == DROPBEAR_SUCCESS) { | 203 if (buf_verify(ses.payload, key, sigtype, signbuf) == DROPBEAR_SUCCESS) { |
155 dropbear_log(LOG_NOTICE, | 204 dropbear_log(LOG_NOTICE, |
156 "Pubkey auth succeeded for '%s' with key %s from %s", | 205 "Pubkey auth succeeded for '%s' with key %s from %s", |
157 ses.authstate.pw_name, fp, svr_ses.addrstring); | 206 ses.authstate.pw_name, fp, svr_ses.addrstring); |
158 send_msg_userauth_success(); | 207 send_msg_userauth_success(); |
208 #if DROPBEAR_PLUGIN | |
209 if ((ses.plugin_session != NULL) && (svr_ses.plugin_instance->auth_success != NULL)) { | |
210 /* Was authenticated through the external plugin. tell plugin that signature verification was ok */ | |
211 svr_ses.plugin_instance->auth_success(ses.plugin_session); | |
212 } | |
213 #endif | |
214 | |
159 } else { | 215 } else { |
160 dropbear_log(LOG_WARNING, | 216 dropbear_log(LOG_WARNING, |
161 "Pubkey auth bad signature for '%s' with key %s from %s", | 217 "Pubkey auth bad signature for '%s' with key %s from %s", |
162 ses.authstate.pw_name, fp, svr_ses.addrstring); | 218 ses.authstate.pw_name, fp, svr_ses.addrstring); |
163 send_msg_userauth_failure(0, 1); | 219 send_msg_userauth_failure(0, 1); |
167 out: | 223 out: |
168 /* cleanup stuff */ | 224 /* cleanup stuff */ |
169 if (signbuf) { | 225 if (signbuf) { |
170 buf_free(signbuf); | 226 buf_free(signbuf); |
171 } | 227 } |
172 if (algo) { | 228 if (sigalgo) { |
173 m_free(algo); | 229 m_free(sigalgo); |
174 } | 230 } |
175 if (key) { | 231 if (key) { |
176 sign_key_free(key); | 232 sign_key_free(key); |
177 key = NULL; | 233 key = NULL; |
178 } | 234 } |
184 } | 240 } |
185 | 241 |
186 /* Reply that the key is valid for auth, this is sent when the user sends | 242 /* Reply that the key is valid for auth, this is sent when the user sends |
187 * a straight copy of their pubkey to test, to avoid having to perform | 243 * a straight copy of their pubkey to test, to avoid having to perform |
188 * expensive signing operations with a worthless key */ | 244 * expensive signing operations with a worthless key */ |
189 static void send_msg_userauth_pk_ok(const char* algo, unsigned int algolen, | 245 static void send_msg_userauth_pk_ok(const char* sigalgo, unsigned int sigalgolen, |
190 const unsigned char* keyblob, unsigned int keybloblen) { | 246 const unsigned char* keyblob, unsigned int keybloblen) { |
191 | 247 |
192 TRACE(("enter send_msg_userauth_pk_ok")) | 248 TRACE(("enter send_msg_userauth_pk_ok")) |
193 CHECKCLEARTOWRITE(); | 249 CHECKCLEARTOWRITE(); |
194 | 250 |
195 buf_putbyte(ses.writepayload, SSH_MSG_USERAUTH_PK_OK); | 251 buf_putbyte(ses.writepayload, SSH_MSG_USERAUTH_PK_OK); |
196 buf_putstring(ses.writepayload, algo, algolen); | 252 buf_putstring(ses.writepayload, sigalgo, sigalgolen); |
197 buf_putstring(ses.writepayload, (const char*)keyblob, keybloblen); | 253 buf_putstring(ses.writepayload, (const char*)keyblob, keybloblen); |
198 | 254 |
199 encrypt_packet(); | 255 encrypt_packet(); |
200 TRACE(("leave send_msg_userauth_pk_ok")) | 256 TRACE(("leave send_msg_userauth_pk_ok")) |
201 | 257 |
308 | 364 |
309 | 365 |
310 /* Checks whether a specified publickey (and associated algorithm) is an | 366 /* Checks whether a specified publickey (and associated algorithm) is an |
311 * acceptable key for authentication */ | 367 * acceptable key for authentication */ |
312 /* Returns DROPBEAR_SUCCESS if key is ok for auth, DROPBEAR_FAILURE otherwise */ | 368 /* Returns DROPBEAR_SUCCESS if key is ok for auth, DROPBEAR_FAILURE otherwise */ |
313 static int checkpubkey(const char* algo, unsigned int algolen, | 369 static int checkpubkey(const char* keyalgo, unsigned int keyalgolen, |
314 const unsigned char* keyblob, unsigned int keybloblen) { | 370 const unsigned char* keyblob, unsigned int keybloblen) { |
315 | 371 |
316 FILE * authfile = NULL; | 372 FILE * authfile = NULL; |
317 char * filename = NULL; | 373 char * filename = NULL; |
318 int ret = DROPBEAR_FAILURE; | 374 int ret = DROPBEAR_FAILURE; |
322 uid_t origuid; | 378 uid_t origuid; |
323 gid_t origgid; | 379 gid_t origgid; |
324 | 380 |
325 TRACE(("enter checkpubkey")) | 381 TRACE(("enter checkpubkey")) |
326 | 382 |
327 /* check that we can use the algo */ | |
328 if (have_algo(algo, algolen, sshhostkey) == DROPBEAR_FAILURE) { | |
329 dropbear_log(LOG_WARNING, | |
330 "Pubkey auth attempt with unknown algo for '%s' from %s", | |
331 ses.authstate.pw_name, svr_ses.addrstring); | |
332 goto out; | |
333 } | |
334 | |
335 /* check file permissions, also whether file exists */ | 383 /* check file permissions, also whether file exists */ |
336 if (checkpubkeyperms() == DROPBEAR_FAILURE) { | 384 if (checkpubkeyperms() == DROPBEAR_FAILURE) { |
337 TRACE(("bad authorized_keys permissions, or file doesn't exist")) | 385 TRACE(("bad authorized_keys permissions, or file doesn't exist")) |
338 goto out; | 386 goto out; |
339 } | 387 } |
381 TRACE(("checkpubkey: authorized_keys EOF reached")) | 429 TRACE(("checkpubkey: authorized_keys EOF reached")) |
382 break; | 430 break; |
383 } | 431 } |
384 line_num++; | 432 line_num++; |
385 | 433 |
386 ret = checkpubkey_line(line, line_num, filename, algo, algolen, keyblob, keybloblen); | 434 ret = checkpubkey_line(line, line_num, filename, keyalgo, keyalgolen, keyblob, keybloblen); |
387 if (ret == DROPBEAR_SUCCESS) { | 435 if (ret == DROPBEAR_SUCCESS) { |
388 break; | 436 break; |
389 } | 437 } |
390 | 438 |
391 /* We continue to the next line otherwise */ | 439 /* We continue to the next line otherwise */ |