1*856ea928SPeter Avalos /* $OpenBSD: auth2-pubkey.c,v 1.26 2010/06/29 23:16:46 djm Exp $ */ 218de8d7fSPeter Avalos /* 318de8d7fSPeter Avalos * Copyright (c) 2000 Markus Friedl. All rights reserved. 418de8d7fSPeter Avalos * 518de8d7fSPeter Avalos * Redistribution and use in source and binary forms, with or without 618de8d7fSPeter Avalos * modification, are permitted provided that the following conditions 718de8d7fSPeter Avalos * are met: 818de8d7fSPeter Avalos * 1. Redistributions of source code must retain the above copyright 918de8d7fSPeter Avalos * notice, this list of conditions and the following disclaimer. 1018de8d7fSPeter Avalos * 2. Redistributions in binary form must reproduce the above copyright 1118de8d7fSPeter Avalos * notice, this list of conditions and the following disclaimer in the 1218de8d7fSPeter Avalos * documentation and/or other materials provided with the distribution. 1318de8d7fSPeter Avalos * 1418de8d7fSPeter Avalos * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 1518de8d7fSPeter Avalos * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 1618de8d7fSPeter Avalos * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 1718de8d7fSPeter Avalos * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 1818de8d7fSPeter Avalos * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 1918de8d7fSPeter Avalos * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 2018de8d7fSPeter Avalos * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 2118de8d7fSPeter Avalos * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 2218de8d7fSPeter Avalos * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 2318de8d7fSPeter Avalos * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 2418de8d7fSPeter Avalos */ 2518de8d7fSPeter Avalos 2618de8d7fSPeter Avalos #include "includes.h" 2718de8d7fSPeter Avalos 2818de8d7fSPeter Avalos #include <sys/types.h> 2918de8d7fSPeter Avalos #include <sys/stat.h> 3018de8d7fSPeter Avalos 3118de8d7fSPeter Avalos #include <fcntl.h> 3218de8d7fSPeter Avalos #include <pwd.h> 3318de8d7fSPeter Avalos #include <stdio.h> 3418de8d7fSPeter Avalos #include <stdarg.h> 35*856ea928SPeter Avalos #include <string.h> 36*856ea928SPeter Avalos #include <time.h> 3718de8d7fSPeter Avalos #include <unistd.h> 3818de8d7fSPeter Avalos 3918de8d7fSPeter Avalos #include "xmalloc.h" 4018de8d7fSPeter Avalos #include "ssh.h" 4118de8d7fSPeter Avalos #include "ssh2.h" 4218de8d7fSPeter Avalos #include "packet.h" 4318de8d7fSPeter Avalos #include "buffer.h" 4418de8d7fSPeter Avalos #include "log.h" 4518de8d7fSPeter Avalos #include "servconf.h" 4618de8d7fSPeter Avalos #include "compat.h" 4718de8d7fSPeter Avalos #include "key.h" 4818de8d7fSPeter Avalos #include "hostfile.h" 4918de8d7fSPeter Avalos #include "auth.h" 5018de8d7fSPeter Avalos #include "pathnames.h" 5118de8d7fSPeter Avalos #include "uidswap.h" 5218de8d7fSPeter Avalos #include "auth-options.h" 5318de8d7fSPeter Avalos #include "canohost.h" 5418de8d7fSPeter Avalos #ifdef GSSAPI 5518de8d7fSPeter Avalos #include "ssh-gss.h" 5618de8d7fSPeter Avalos #endif 5718de8d7fSPeter Avalos #include "monitor_wrap.h" 5818de8d7fSPeter Avalos #include "misc.h" 59*856ea928SPeter Avalos #include "authfile.h" 60*856ea928SPeter Avalos #include "match.h" 6118de8d7fSPeter Avalos 6218de8d7fSPeter Avalos /* import */ 6318de8d7fSPeter Avalos extern ServerOptions options; 6418de8d7fSPeter Avalos extern u_char *session_id2; 6518de8d7fSPeter Avalos extern u_int session_id2_len; 6618de8d7fSPeter Avalos 6718de8d7fSPeter Avalos static int 6818de8d7fSPeter Avalos userauth_pubkey(Authctxt *authctxt) 6918de8d7fSPeter Avalos { 7018de8d7fSPeter Avalos Buffer b; 7118de8d7fSPeter Avalos Key *key = NULL; 7218de8d7fSPeter Avalos char *pkalg; 7318de8d7fSPeter Avalos u_char *pkblob, *sig; 7418de8d7fSPeter Avalos u_int alen, blen, slen; 7518de8d7fSPeter Avalos int have_sig, pktype; 7618de8d7fSPeter Avalos int authenticated = 0; 7718de8d7fSPeter Avalos 7818de8d7fSPeter Avalos if (!authctxt->valid) { 7918de8d7fSPeter Avalos debug2("userauth_pubkey: disabled because of invalid user"); 8018de8d7fSPeter Avalos return 0; 8118de8d7fSPeter Avalos } 8218de8d7fSPeter Avalos have_sig = packet_get_char(); 8318de8d7fSPeter Avalos if (datafellows & SSH_BUG_PKAUTH) { 8418de8d7fSPeter Avalos debug2("userauth_pubkey: SSH_BUG_PKAUTH"); 8518de8d7fSPeter Avalos /* no explicit pkalg given */ 8618de8d7fSPeter Avalos pkblob = packet_get_string(&blen); 8718de8d7fSPeter Avalos buffer_init(&b); 8818de8d7fSPeter Avalos buffer_append(&b, pkblob, blen); 8918de8d7fSPeter Avalos /* so we have to extract the pkalg from the pkblob */ 9018de8d7fSPeter Avalos pkalg = buffer_get_string(&b, &alen); 9118de8d7fSPeter Avalos buffer_free(&b); 9218de8d7fSPeter Avalos } else { 9318de8d7fSPeter Avalos pkalg = packet_get_string(&alen); 9418de8d7fSPeter Avalos pkblob = packet_get_string(&blen); 9518de8d7fSPeter Avalos } 9618de8d7fSPeter Avalos pktype = key_type_from_name(pkalg); 9718de8d7fSPeter Avalos if (pktype == KEY_UNSPEC) { 9818de8d7fSPeter Avalos /* this is perfectly legal */ 9918de8d7fSPeter Avalos logit("userauth_pubkey: unsupported public key algorithm: %s", 10018de8d7fSPeter Avalos pkalg); 10118de8d7fSPeter Avalos goto done; 10218de8d7fSPeter Avalos } 10318de8d7fSPeter Avalos key = key_from_blob(pkblob, blen); 10418de8d7fSPeter Avalos if (key == NULL) { 10518de8d7fSPeter Avalos error("userauth_pubkey: cannot decode key: %s", pkalg); 10618de8d7fSPeter Avalos goto done; 10718de8d7fSPeter Avalos } 10818de8d7fSPeter Avalos if (key->type != pktype) { 10918de8d7fSPeter Avalos error("userauth_pubkey: type mismatch for decoded key " 11018de8d7fSPeter Avalos "(received %d, expected %d)", key->type, pktype); 11118de8d7fSPeter Avalos goto done; 11218de8d7fSPeter Avalos } 11318de8d7fSPeter Avalos if (have_sig) { 11418de8d7fSPeter Avalos sig = packet_get_string(&slen); 11518de8d7fSPeter Avalos packet_check_eom(); 11618de8d7fSPeter Avalos buffer_init(&b); 11718de8d7fSPeter Avalos if (datafellows & SSH_OLD_SESSIONID) { 11818de8d7fSPeter Avalos buffer_append(&b, session_id2, session_id2_len); 11918de8d7fSPeter Avalos } else { 12018de8d7fSPeter Avalos buffer_put_string(&b, session_id2, session_id2_len); 12118de8d7fSPeter Avalos } 12218de8d7fSPeter Avalos /* reconstruct packet */ 12318de8d7fSPeter Avalos buffer_put_char(&b, SSH2_MSG_USERAUTH_REQUEST); 12418de8d7fSPeter Avalos buffer_put_cstring(&b, authctxt->user); 12518de8d7fSPeter Avalos buffer_put_cstring(&b, 12618de8d7fSPeter Avalos datafellows & SSH_BUG_PKSERVICE ? 12718de8d7fSPeter Avalos "ssh-userauth" : 12818de8d7fSPeter Avalos authctxt->service); 12918de8d7fSPeter Avalos if (datafellows & SSH_BUG_PKAUTH) { 13018de8d7fSPeter Avalos buffer_put_char(&b, have_sig); 13118de8d7fSPeter Avalos } else { 13218de8d7fSPeter Avalos buffer_put_cstring(&b, "publickey"); 13318de8d7fSPeter Avalos buffer_put_char(&b, have_sig); 13418de8d7fSPeter Avalos buffer_put_cstring(&b, pkalg); 13518de8d7fSPeter Avalos } 13618de8d7fSPeter Avalos buffer_put_string(&b, pkblob, blen); 13718de8d7fSPeter Avalos #ifdef DEBUG_PK 13818de8d7fSPeter Avalos buffer_dump(&b); 13918de8d7fSPeter Avalos #endif 14018de8d7fSPeter Avalos /* test for correct signature */ 14118de8d7fSPeter Avalos authenticated = 0; 14218de8d7fSPeter Avalos if (PRIVSEP(user_key_allowed(authctxt->pw, key)) && 14318de8d7fSPeter Avalos PRIVSEP(key_verify(key, sig, slen, buffer_ptr(&b), 14418de8d7fSPeter Avalos buffer_len(&b))) == 1) 14518de8d7fSPeter Avalos authenticated = 1; 14618de8d7fSPeter Avalos buffer_free(&b); 14718de8d7fSPeter Avalos xfree(sig); 14818de8d7fSPeter Avalos } else { 14918de8d7fSPeter Avalos debug("test whether pkalg/pkblob are acceptable"); 15018de8d7fSPeter Avalos packet_check_eom(); 15118de8d7fSPeter Avalos 15218de8d7fSPeter Avalos /* XXX fake reply and always send PK_OK ? */ 15318de8d7fSPeter Avalos /* 15418de8d7fSPeter Avalos * XXX this allows testing whether a user is allowed 15518de8d7fSPeter Avalos * to login: if you happen to have a valid pubkey this 15618de8d7fSPeter Avalos * message is sent. the message is NEVER sent at all 15718de8d7fSPeter Avalos * if a user is not allowed to login. is this an 15818de8d7fSPeter Avalos * issue? -markus 15918de8d7fSPeter Avalos */ 16018de8d7fSPeter Avalos if (PRIVSEP(user_key_allowed(authctxt->pw, key))) { 16118de8d7fSPeter Avalos packet_start(SSH2_MSG_USERAUTH_PK_OK); 16218de8d7fSPeter Avalos packet_put_string(pkalg, alen); 16318de8d7fSPeter Avalos packet_put_string(pkblob, blen); 16418de8d7fSPeter Avalos packet_send(); 16518de8d7fSPeter Avalos packet_write_wait(); 16618de8d7fSPeter Avalos authctxt->postponed = 1; 16718de8d7fSPeter Avalos } 16818de8d7fSPeter Avalos } 16918de8d7fSPeter Avalos if (authenticated != 1) 17018de8d7fSPeter Avalos auth_clear_options(); 17118de8d7fSPeter Avalos done: 17218de8d7fSPeter Avalos debug2("userauth_pubkey: authenticated %d pkalg %s", authenticated, pkalg); 17318de8d7fSPeter Avalos if (key != NULL) 17418de8d7fSPeter Avalos key_free(key); 17518de8d7fSPeter Avalos xfree(pkalg); 17618de8d7fSPeter Avalos xfree(pkblob); 17718de8d7fSPeter Avalos return authenticated; 17818de8d7fSPeter Avalos } 17918de8d7fSPeter Avalos 180*856ea928SPeter Avalos static int 181*856ea928SPeter Avalos match_principals_option(const char *principal_list, struct KeyCert *cert) 182*856ea928SPeter Avalos { 183*856ea928SPeter Avalos char *result; 184*856ea928SPeter Avalos u_int i; 185*856ea928SPeter Avalos 186*856ea928SPeter Avalos /* XXX percent_expand() sequences for authorized_principals? */ 187*856ea928SPeter Avalos 188*856ea928SPeter Avalos for (i = 0; i < cert->nprincipals; i++) { 189*856ea928SPeter Avalos if ((result = match_list(cert->principals[i], 190*856ea928SPeter Avalos principal_list, NULL)) != NULL) { 191*856ea928SPeter Avalos debug3("matched principal from key options \"%.100s\"", 192*856ea928SPeter Avalos result); 193*856ea928SPeter Avalos xfree(result); 194*856ea928SPeter Avalos return 1; 195*856ea928SPeter Avalos } 196*856ea928SPeter Avalos } 197*856ea928SPeter Avalos return 0; 198*856ea928SPeter Avalos } 199*856ea928SPeter Avalos 200*856ea928SPeter Avalos static int 201*856ea928SPeter Avalos match_principals_file(char *file, struct passwd *pw, struct KeyCert *cert) 202*856ea928SPeter Avalos { 203*856ea928SPeter Avalos FILE *f; 204*856ea928SPeter Avalos char line[SSH_MAX_PUBKEY_BYTES], *cp, *ep, *line_opts; 205*856ea928SPeter Avalos u_long linenum = 0; 206*856ea928SPeter Avalos u_int i; 207*856ea928SPeter Avalos 208*856ea928SPeter Avalos temporarily_use_uid(pw); 209*856ea928SPeter Avalos debug("trying authorized principals file %s", file); 210*856ea928SPeter Avalos if ((f = auth_openprincipals(file, pw, options.strict_modes)) == NULL) { 211*856ea928SPeter Avalos restore_uid(); 212*856ea928SPeter Avalos return 0; 213*856ea928SPeter Avalos } 214*856ea928SPeter Avalos while (read_keyfile_line(f, file, line, sizeof(line), &linenum) != -1) { 215*856ea928SPeter Avalos /* Skip leading whitespace. */ 216*856ea928SPeter Avalos for (cp = line; *cp == ' ' || *cp == '\t'; cp++) 217*856ea928SPeter Avalos ; 218*856ea928SPeter Avalos /* Skip blank and comment lines. */ 219*856ea928SPeter Avalos if ((ep = strchr(cp, '#')) != NULL) 220*856ea928SPeter Avalos *ep = '\0'; 221*856ea928SPeter Avalos if (!*cp || *cp == '\n') 222*856ea928SPeter Avalos continue; 223*856ea928SPeter Avalos /* Trim trailing whitespace. */ 224*856ea928SPeter Avalos ep = cp + strlen(cp) - 1; 225*856ea928SPeter Avalos while (ep > cp && (*ep == '\n' || *ep == ' ' || *ep == '\t')) 226*856ea928SPeter Avalos *ep-- = '\0'; 227*856ea928SPeter Avalos /* 228*856ea928SPeter Avalos * If the line has internal whitespace then assume it has 229*856ea928SPeter Avalos * key options. 230*856ea928SPeter Avalos */ 231*856ea928SPeter Avalos line_opts = NULL; 232*856ea928SPeter Avalos if ((ep = strrchr(cp, ' ')) != NULL || 233*856ea928SPeter Avalos (ep = strrchr(cp, '\t')) != NULL) { 234*856ea928SPeter Avalos for (; *ep == ' ' || *ep == '\t'; ep++) 235*856ea928SPeter Avalos ;; 236*856ea928SPeter Avalos line_opts = cp; 237*856ea928SPeter Avalos cp = ep; 238*856ea928SPeter Avalos } 239*856ea928SPeter Avalos for (i = 0; i < cert->nprincipals; i++) { 240*856ea928SPeter Avalos if (strcmp(cp, cert->principals[i]) == 0) { 241*856ea928SPeter Avalos debug3("matched principal from file \"%.100s\"", 242*856ea928SPeter Avalos cert->principals[i]); 243*856ea928SPeter Avalos if (auth_parse_options(pw, line_opts, 244*856ea928SPeter Avalos file, linenum) != 1) 245*856ea928SPeter Avalos continue; 246*856ea928SPeter Avalos fclose(f); 247*856ea928SPeter Avalos restore_uid(); 248*856ea928SPeter Avalos return 1; 249*856ea928SPeter Avalos } 250*856ea928SPeter Avalos } 251*856ea928SPeter Avalos } 252*856ea928SPeter Avalos fclose(f); 253*856ea928SPeter Avalos restore_uid(); 254*856ea928SPeter Avalos return 0; 255*856ea928SPeter Avalos } 256*856ea928SPeter Avalos 25718de8d7fSPeter Avalos /* return 1 if user allows given key */ 25818de8d7fSPeter Avalos static int 25918de8d7fSPeter Avalos user_key_allowed2(struct passwd *pw, Key *key, char *file) 26018de8d7fSPeter Avalos { 26118de8d7fSPeter Avalos char line[SSH_MAX_PUBKEY_BYTES]; 262*856ea928SPeter Avalos const char *reason; 26318de8d7fSPeter Avalos int found_key = 0; 26418de8d7fSPeter Avalos FILE *f; 26518de8d7fSPeter Avalos u_long linenum = 0; 26618de8d7fSPeter Avalos Key *found; 26718de8d7fSPeter Avalos char *fp; 26818de8d7fSPeter Avalos 26918de8d7fSPeter Avalos /* Temporarily use the user's uid. */ 27018de8d7fSPeter Avalos temporarily_use_uid(pw); 27118de8d7fSPeter Avalos 27218de8d7fSPeter Avalos debug("trying public key file %s", file); 27318de8d7fSPeter Avalos f = auth_openkeyfile(file, pw, options.strict_modes); 27418de8d7fSPeter Avalos 27518de8d7fSPeter Avalos if (!f) { 27618de8d7fSPeter Avalos restore_uid(); 27718de8d7fSPeter Avalos return 0; 27818de8d7fSPeter Avalos } 27918de8d7fSPeter Avalos 28018de8d7fSPeter Avalos found_key = 0; 281*856ea928SPeter Avalos found = key_new(key_is_cert(key) ? KEY_UNSPEC : key->type); 28218de8d7fSPeter Avalos 28318de8d7fSPeter Avalos while (read_keyfile_line(f, file, line, sizeof(line), &linenum) != -1) { 28418de8d7fSPeter Avalos char *cp, *key_options = NULL; 28518de8d7fSPeter Avalos 286*856ea928SPeter Avalos auth_clear_options(); 287*856ea928SPeter Avalos 28818de8d7fSPeter Avalos /* Skip leading whitespace, empty and comment lines. */ 28918de8d7fSPeter Avalos for (cp = line; *cp == ' ' || *cp == '\t'; cp++) 29018de8d7fSPeter Avalos ; 29118de8d7fSPeter Avalos if (!*cp || *cp == '\n' || *cp == '#') 29218de8d7fSPeter Avalos continue; 29318de8d7fSPeter Avalos 29418de8d7fSPeter Avalos if (key_read(found, &cp) != 1) { 29518de8d7fSPeter Avalos /* no key? check if there are options for this key */ 29618de8d7fSPeter Avalos int quoted = 0; 29718de8d7fSPeter Avalos debug2("user_key_allowed: check options: '%s'", cp); 29818de8d7fSPeter Avalos key_options = cp; 29918de8d7fSPeter Avalos for (; *cp && (quoted || (*cp != ' ' && *cp != '\t')); cp++) { 30018de8d7fSPeter Avalos if (*cp == '\\' && cp[1] == '"') 30118de8d7fSPeter Avalos cp++; /* Skip both */ 30218de8d7fSPeter Avalos else if (*cp == '"') 30318de8d7fSPeter Avalos quoted = !quoted; 30418de8d7fSPeter Avalos } 30518de8d7fSPeter Avalos /* Skip remaining whitespace. */ 30618de8d7fSPeter Avalos for (; *cp == ' ' || *cp == '\t'; cp++) 30718de8d7fSPeter Avalos ; 30818de8d7fSPeter Avalos if (key_read(found, &cp) != 1) { 30918de8d7fSPeter Avalos debug2("user_key_allowed: advance: '%s'", cp); 31018de8d7fSPeter Avalos /* still no key? advance to next line*/ 31118de8d7fSPeter Avalos continue; 31218de8d7fSPeter Avalos } 31318de8d7fSPeter Avalos } 314*856ea928SPeter Avalos if (key_is_cert(key)) { 315*856ea928SPeter Avalos if (!key_equal(found, key->cert->signature_key)) 316*856ea928SPeter Avalos continue; 317*856ea928SPeter Avalos if (auth_parse_options(pw, key_options, file, 318*856ea928SPeter Avalos linenum) != 1) 319*856ea928SPeter Avalos continue; 320*856ea928SPeter Avalos if (!key_is_cert_authority) 321*856ea928SPeter Avalos continue; 322*856ea928SPeter Avalos fp = key_fingerprint(found, SSH_FP_MD5, 323*856ea928SPeter Avalos SSH_FP_HEX); 324*856ea928SPeter Avalos debug("matching CA found: file %s, line %lu, %s %s", 325*856ea928SPeter Avalos file, linenum, key_type(found), fp); 326*856ea928SPeter Avalos /* 327*856ea928SPeter Avalos * If the user has specified a list of principals as 328*856ea928SPeter Avalos * a key option, then prefer that list to matching 329*856ea928SPeter Avalos * their username in the certificate principals list. 330*856ea928SPeter Avalos */ 331*856ea928SPeter Avalos if (authorized_principals != NULL && 332*856ea928SPeter Avalos !match_principals_option(authorized_principals, 333*856ea928SPeter Avalos key->cert)) { 334*856ea928SPeter Avalos reason = "Certificate does not contain an " 335*856ea928SPeter Avalos "authorized principal"; 336*856ea928SPeter Avalos fail_reason: 337*856ea928SPeter Avalos xfree(fp); 338*856ea928SPeter Avalos error("%s", reason); 339*856ea928SPeter Avalos auth_debug_add("%s", reason); 340*856ea928SPeter Avalos continue; 341*856ea928SPeter Avalos } 342*856ea928SPeter Avalos if (key_cert_check_authority(key, 0, 0, 343*856ea928SPeter Avalos authorized_principals == NULL ? pw->pw_name : NULL, 344*856ea928SPeter Avalos &reason) != 0) 345*856ea928SPeter Avalos goto fail_reason; 346*856ea928SPeter Avalos if (auth_cert_options(key, pw) != 0) { 347*856ea928SPeter Avalos xfree(fp); 348*856ea928SPeter Avalos continue; 349*856ea928SPeter Avalos } 350*856ea928SPeter Avalos verbose("Accepted certificate ID \"%s\" " 351*856ea928SPeter Avalos "signed by %s CA %s via %s", key->cert->key_id, 352*856ea928SPeter Avalos key_type(found), fp, file); 353*856ea928SPeter Avalos xfree(fp); 354*856ea928SPeter Avalos found_key = 1; 355*856ea928SPeter Avalos break; 356*856ea928SPeter Avalos } else if (key_equal(found, key)) { 357*856ea928SPeter Avalos if (auth_parse_options(pw, key_options, file, 358*856ea928SPeter Avalos linenum) != 1) 359*856ea928SPeter Avalos continue; 360*856ea928SPeter Avalos if (key_is_cert_authority) 361*856ea928SPeter Avalos continue; 36218de8d7fSPeter Avalos found_key = 1; 36318de8d7fSPeter Avalos debug("matching key found: file %s, line %lu", 36418de8d7fSPeter Avalos file, linenum); 36518de8d7fSPeter Avalos fp = key_fingerprint(found, SSH_FP_MD5, SSH_FP_HEX); 36618de8d7fSPeter Avalos verbose("Found matching %s key: %s", 36718de8d7fSPeter Avalos key_type(found), fp); 36818de8d7fSPeter Avalos xfree(fp); 36918de8d7fSPeter Avalos break; 37018de8d7fSPeter Avalos } 37118de8d7fSPeter Avalos } 37218de8d7fSPeter Avalos restore_uid(); 37318de8d7fSPeter Avalos fclose(f); 37418de8d7fSPeter Avalos key_free(found); 37518de8d7fSPeter Avalos if (!found_key) 37618de8d7fSPeter Avalos debug2("key not found"); 37718de8d7fSPeter Avalos return found_key; 37818de8d7fSPeter Avalos } 37918de8d7fSPeter Avalos 380*856ea928SPeter Avalos /* Authenticate a certificate key against TrustedUserCAKeys */ 381*856ea928SPeter Avalos static int 382*856ea928SPeter Avalos user_cert_trusted_ca(struct passwd *pw, Key *key) 383*856ea928SPeter Avalos { 384*856ea928SPeter Avalos char *ca_fp, *principals_file = NULL; 385*856ea928SPeter Avalos const char *reason; 386*856ea928SPeter Avalos int ret = 0; 387*856ea928SPeter Avalos 388*856ea928SPeter Avalos if (!key_is_cert(key) || options.trusted_user_ca_keys == NULL) 389*856ea928SPeter Avalos return 0; 390*856ea928SPeter Avalos 391*856ea928SPeter Avalos ca_fp = key_fingerprint(key->cert->signature_key, 392*856ea928SPeter Avalos SSH_FP_MD5, SSH_FP_HEX); 393*856ea928SPeter Avalos 394*856ea928SPeter Avalos if (key_in_file(key->cert->signature_key, 395*856ea928SPeter Avalos options.trusted_user_ca_keys, 1) != 1) { 396*856ea928SPeter Avalos debug2("%s: CA %s %s is not listed in %s", __func__, 397*856ea928SPeter Avalos key_type(key->cert->signature_key), ca_fp, 398*856ea928SPeter Avalos options.trusted_user_ca_keys); 399*856ea928SPeter Avalos goto out; 400*856ea928SPeter Avalos } 401*856ea928SPeter Avalos /* 402*856ea928SPeter Avalos * If AuthorizedPrincipals is in use, then compare the certificate 403*856ea928SPeter Avalos * principals against the names in that file rather than matching 404*856ea928SPeter Avalos * against the username. 405*856ea928SPeter Avalos */ 406*856ea928SPeter Avalos if ((principals_file = authorized_principals_file(pw)) != NULL) { 407*856ea928SPeter Avalos if (!match_principals_file(principals_file, pw, key->cert)) { 408*856ea928SPeter Avalos reason = "Certificate does not contain an " 409*856ea928SPeter Avalos "authorized principal"; 410*856ea928SPeter Avalos fail_reason: 411*856ea928SPeter Avalos error("%s", reason); 412*856ea928SPeter Avalos auth_debug_add("%s", reason); 413*856ea928SPeter Avalos goto out; 414*856ea928SPeter Avalos } 415*856ea928SPeter Avalos } 416*856ea928SPeter Avalos if (key_cert_check_authority(key, 0, 1, 417*856ea928SPeter Avalos principals_file == NULL ? pw->pw_name : NULL, &reason) != 0) 418*856ea928SPeter Avalos goto fail_reason; 419*856ea928SPeter Avalos if (auth_cert_options(key, pw) != 0) 420*856ea928SPeter Avalos goto out; 421*856ea928SPeter Avalos 422*856ea928SPeter Avalos verbose("Accepted certificate ID \"%s\" signed by %s CA %s via %s", 423*856ea928SPeter Avalos key->cert->key_id, key_type(key->cert->signature_key), ca_fp, 424*856ea928SPeter Avalos options.trusted_user_ca_keys); 425*856ea928SPeter Avalos ret = 1; 426*856ea928SPeter Avalos 427*856ea928SPeter Avalos out: 428*856ea928SPeter Avalos if (principals_file != NULL) 429*856ea928SPeter Avalos xfree(principals_file); 430*856ea928SPeter Avalos if (ca_fp != NULL) 431*856ea928SPeter Avalos xfree(ca_fp); 432*856ea928SPeter Avalos return ret; 433*856ea928SPeter Avalos } 434*856ea928SPeter Avalos 43518de8d7fSPeter Avalos /* check whether given key is in .ssh/authorized_keys* */ 43618de8d7fSPeter Avalos int 43718de8d7fSPeter Avalos user_key_allowed(struct passwd *pw, Key *key) 43818de8d7fSPeter Avalos { 43918de8d7fSPeter Avalos int success; 44018de8d7fSPeter Avalos char *file; 44118de8d7fSPeter Avalos 442*856ea928SPeter Avalos if (auth_key_is_revoked(key)) 443*856ea928SPeter Avalos return 0; 444*856ea928SPeter Avalos if (key_is_cert(key) && auth_key_is_revoked(key->cert->signature_key)) 445*856ea928SPeter Avalos return 0; 446*856ea928SPeter Avalos 447*856ea928SPeter Avalos success = user_cert_trusted_ca(pw, key); 448*856ea928SPeter Avalos if (success) 449*856ea928SPeter Avalos return success; 450*856ea928SPeter Avalos 45118de8d7fSPeter Avalos file = authorized_keys_file(pw); 45218de8d7fSPeter Avalos success = user_key_allowed2(pw, key, file); 45318de8d7fSPeter Avalos xfree(file); 45418de8d7fSPeter Avalos if (success) 45518de8d7fSPeter Avalos return success; 45618de8d7fSPeter Avalos 45718de8d7fSPeter Avalos /* try suffix "2" for backward compat, too */ 45818de8d7fSPeter Avalos file = authorized_keys_file2(pw); 45918de8d7fSPeter Avalos success = user_key_allowed2(pw, key, file); 46018de8d7fSPeter Avalos xfree(file); 46118de8d7fSPeter Avalos return success; 46218de8d7fSPeter Avalos } 46318de8d7fSPeter Avalos 46418de8d7fSPeter Avalos Authmethod method_pubkey = { 46518de8d7fSPeter Avalos "publickey", 46618de8d7fSPeter Avalos userauth_pubkey, 46718de8d7fSPeter Avalos &options.pubkey_authentication 46818de8d7fSPeter Avalos }; 469