[BACK]Return to authfd.c CVS log [TXT][DIR] Up to [local] / src / usr.bin / ssh

Annotation of src/usr.bin/ssh/authfd.c, Revision 1.9

1.1       deraadt     1: /*
                      2:
                      3: authfd.c
                      4:
                      5: Author: Tatu Ylonen <ylo@cs.hut.fi>
                      6:
                      7: Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
                      8:                    All rights reserved
                      9:
                     10: Created: Wed Mar 29 01:30:28 1995 ylo
                     11:
                     12: Functions for connecting the local authentication agent.
                     13:
                     14: */
                     15:
                     16: #include "includes.h"
1.9     ! markus     17: RCSID("$Id: authfd.c,v 1.8 1999/10/14 18:17:41 markus Exp $");
1.1       deraadt    18:
                     19: #include "ssh.h"
                     20: #include "rsa.h"
                     21: #include "authfd.h"
                     22: #include "buffer.h"
                     23: #include "bufaux.h"
                     24: #include "xmalloc.h"
                     25: #include "getput.h"
                     26:
1.2       provos     27: #include <ssl/rsa.h>
                     28:
1.1       deraadt    29: /* Returns the number of the authentication fd, or -1 if there is none. */
                     30:
1.2       provos     31: int
1.8       markus     32: ssh_get_authentication_socket()
1.1       deraadt    33: {
1.7       markus     34:   const char *authsocket;
1.1       deraadt    35:   int sock;
                     36:   struct sockaddr_un sunaddr;
                     37:
                     38:   authsocket = getenv(SSH_AUTHSOCKET_ENV_NAME);
                     39:   if (!authsocket)
                     40:     return -1;
                     41:
                     42:   sunaddr.sun_family = AF_UNIX;
1.3       deraadt    43:   strlcpy(sunaddr.sun_path, authsocket, sizeof(sunaddr.sun_path));
1.1       deraadt    44:
                     45:   sock = socket(AF_UNIX, SOCK_STREAM, 0);
                     46:   if (sock < 0)
                     47:     return -1;
                     48:
1.4       deraadt    49:   if (connect(sock, (struct sockaddr *)&sunaddr, sizeof(sunaddr)) < 0)
1.1       deraadt    50:     {
                     51:       close(sock);
                     52:       return -1;
                     53:     }
                     54:
                     55:   return sock;
                     56: }
                     57:
                     58: /* Closes the agent socket if it should be closed (depends on how it was
                     59:    obtained).  The argument must have been returned by
1.8       markus     60:    ssh_get_authentication_socket(). */
1.1       deraadt    61:
                     62: void ssh_close_authentication_socket(int sock)
                     63: {
                     64:   if (getenv(SSH_AUTHSOCKET_ENV_NAME))
                     65:     close(sock);
                     66: }
                     67:
                     68: /* Opens and connects a private socket for communication with the
                     69:    authentication agent.  Returns the file descriptor (which must be
                     70:    shut down and closed by the caller when no longer needed).
                     71:    Returns NULL if an error occurred and the connection could not be
                     72:    opened. */
                     73:
                     74: AuthenticationConnection *ssh_get_authentication_connection()
                     75: {
                     76:   AuthenticationConnection *auth;
                     77:   int sock;
                     78:
1.8       markus     79:   sock = ssh_get_authentication_socket();
1.1       deraadt    80:
                     81:   /* Fail if we couldn't obtain a connection.  This happens if we exited
                     82:      due to a timeout. */
                     83:   if (sock < 0)
                     84:     return NULL;
                     85:
                     86:   /* Applocate the connection structure and initialize it. */
                     87:   auth = xmalloc(sizeof(*auth));
                     88:   auth->fd = sock;
                     89:   buffer_init(&auth->packet);
                     90:   buffer_init(&auth->identities);
                     91:   auth->howmany = 0;
                     92:
                     93:   return auth;
                     94: }
                     95:
                     96: /* Closes the connection to the authentication agent and frees any associated
                     97:    memory. */
                     98:
                     99: void ssh_close_authentication_connection(AuthenticationConnection *ac)
                    100: {
                    101:   buffer_free(&ac->packet);
                    102:   buffer_free(&ac->identities);
                    103:   close(ac->fd);
1.8       markus    104:   /* Free the connection data structure. */
                    105:   xfree(ac);
1.1       deraadt   106: }
                    107:
                    108: /* Returns the first authentication identity held by the agent.
                    109:    Returns true if an identity is available, 0 otherwise.
                    110:    The caller must initialize the integers before the call, and free the
                    111:    comment after a successful call (before calling ssh_get_next_identity). */
                    112:
1.2       provos    113: int
                    114: ssh_get_first_identity(AuthenticationConnection *auth,
1.9     ! markus    115:                       BIGNUM *e, BIGNUM *n, char **comment)
1.1       deraadt   116: {
                    117:   unsigned char msg[8192];
                    118:   int len, l;
                    119:
                    120:   /* Send a message to the agent requesting for a list of the identities
                    121:      it can represent. */
                    122:   msg[0] = 0;
                    123:   msg[1] = 0;
                    124:   msg[2] = 0;
                    125:   msg[3] = 1;
                    126:   msg[4] = SSH_AGENTC_REQUEST_RSA_IDENTITIES;
                    127:   if (write(auth->fd, msg, 5) != 5)
                    128:     {
                    129:       error("write auth->fd: %.100s", strerror(errno));
                    130:       return 0;
                    131:     }
                    132:
                    133:   /* Read the length of the response.  XXX implement timeouts here. */
                    134:   len = 4;
                    135:   while (len > 0)
                    136:     {
                    137:       l = read(auth->fd, msg + 4 - len, len);
                    138:       if (l <= 0)
                    139:        {
                    140:          error("read auth->fd: %.100s", strerror(errno));
                    141:          return 0;
                    142:        }
                    143:       len -= l;
                    144:     }
                    145:
                    146:   /* Extract the length, and check it for sanity.  (We cannot trust
                    147:      authentication agents). */
                    148:   len = GET_32BIT(msg);
                    149:   if (len < 1 || len > 256*1024)
                    150:     fatal("Authentication reply message too long: %d\n", len);
                    151:
                    152:   /* Read the packet itself. */
                    153:   buffer_clear(&auth->identities);
                    154:   while (len > 0)
                    155:     {
                    156:       l = len;
                    157:       if (l > sizeof(msg))
                    158:        l = sizeof(msg);
                    159:       l = read(auth->fd, msg, l);
                    160:       if (l <= 0)
                    161:        fatal("Incomplete authentication reply.");
                    162:       buffer_append(&auth->identities, (char *)msg, l);
                    163:       len -= l;
                    164:     }
                    165:
                    166:   /* Get message type, and verify that we got a proper answer. */
                    167:   buffer_get(&auth->identities, (char *)msg, 1);
                    168:   if (msg[0] != SSH_AGENT_RSA_IDENTITIES_ANSWER)
                    169:     fatal("Bad authentication reply message type: %d", msg[0]);
                    170:
                    171:   /* Get the number of entries in the response and check it for sanity. */
                    172:   auth->howmany = buffer_get_int(&auth->identities);
                    173:   if (auth->howmany > 1024)
                    174:     fatal("Too many identities in authentication reply: %d\n", auth->howmany);
                    175:
                    176:   /* Return the first entry (if any). */
1.9     ! markus    177:   return ssh_get_next_identity(auth, e, n, comment);
1.1       deraadt   178: }
                    179:
                    180: /* Returns the next authentication identity for the agent.  Other functions
                    181:    can be called between this and ssh_get_first_identity or two calls of this
                    182:    function.  This returns 0 if there are no more identities.  The caller
                    183:    must free comment after a successful return. */
                    184:
1.2       provos    185: int
                    186: ssh_get_next_identity(AuthenticationConnection *auth,
1.9     ! markus    187:                      BIGNUM *e, BIGNUM *n, char **comment)
1.1       deraadt   188: {
1.9     ! markus    189:   unsigned int bits;
        !           190:
1.1       deraadt   191:   /* Return failure if no more entries. */
                    192:   if (auth->howmany <= 0)
                    193:     return 0;
                    194:
                    195:   /* Get the next entry from the packet.  These will abort with a fatal
                    196:      error if the packet is too short or contains corrupt data. */
1.9     ! markus    197:   bits = buffer_get_int(&auth->identities);
1.2       provos    198:   buffer_get_bignum(&auth->identities, e);
                    199:   buffer_get_bignum(&auth->identities, n);
1.1       deraadt   200:   *comment = buffer_get_string(&auth->identities, NULL);
                    201:
1.9     ! markus    202:   if (bits != BN_num_bits(n))
        !           203:     error("Warning: keysize mismatch: actual %d, announced %s",
        !           204:          BN_num_bits(n), bits);
        !           205:
1.1       deraadt   206:   /* Decrement the number of remaining entries. */
                    207:   auth->howmany--;
                    208:
                    209:   return 1;
                    210: }
                    211:
                    212: /* Generates a random challenge, sends it to the agent, and waits for response
                    213:    from the agent.  Returns true (non-zero) if the agent gave the correct
                    214:    answer, zero otherwise.  Response type selects the style of response
                    215:    desired, with 0 corresponding to protocol version 1.0 (no longer supported)
                    216:    and 1 corresponding to protocol version 1.1. */
                    217:
1.2       provos    218: int
                    219: ssh_decrypt_challenge(AuthenticationConnection *auth,
1.9     ! markus    220:                      BIGNUM *e, BIGNUM *n, BIGNUM *challenge,
1.2       provos    221:                      unsigned char session_id[16],
                    222:                      unsigned int response_type,
                    223:                      unsigned char response[16])
1.1       deraadt   224: {
                    225:   Buffer buffer;
                    226:   unsigned char buf[8192];
                    227:   int len, l, i;
                    228:
                    229:   /* Response type 0 is no longer supported. */
                    230:   if (response_type == 0)
                    231:     fatal("Compatibility with ssh protocol version 1.0 no longer supported.");
                    232:
                    233:   /* Format a message to the agent. */
                    234:   buf[0] = SSH_AGENTC_RSA_CHALLENGE;
                    235:   buffer_init(&buffer);
                    236:   buffer_append(&buffer, (char *)buf, 1);
1.9     ! markus    237:   buffer_put_int(&buffer, BN_num_bits(n));
1.2       provos    238:   buffer_put_bignum(&buffer, e);
                    239:   buffer_put_bignum(&buffer, n);
                    240:   buffer_put_bignum(&buffer, challenge);
1.1       deraadt   241:   buffer_append(&buffer, (char *)session_id, 16);
                    242:   buffer_put_int(&buffer, response_type);
                    243:
                    244:   /* Get the length of the message, and format it in the buffer. */
                    245:   len = buffer_len(&buffer);
                    246:   PUT_32BIT(buf, len);
                    247:
                    248:   /* Send the length and then the packet to the agent. */
                    249:   if (write(auth->fd, buf, 4) != 4 ||
                    250:       write(auth->fd, buffer_ptr(&buffer), buffer_len(&buffer)) !=
                    251:         buffer_len(&buffer))
                    252:     {
                    253:       error("Error writing to authentication socket.");
                    254:     error_cleanup:
                    255:       buffer_free(&buffer);
                    256:       return 0;
                    257:     }
                    258:
                    259:   /* Wait for response from the agent.  First read the length of the
                    260:      response packet. */
                    261:   len = 4;
                    262:   while (len > 0)
                    263:     {
                    264:       l = read(auth->fd, buf + 4 - len, len);
                    265:       if (l <= 0)
                    266:        {
                    267:          error("Error reading response length from authentication socket.");
                    268:          goto error_cleanup;
                    269:        }
                    270:       len -= l;
                    271:     }
                    272:
                    273:   /* Extract the length, and check it for sanity. */
                    274:   len = GET_32BIT(buf);
                    275:   if (len > 256*1024)
                    276:     fatal("Authentication response too long: %d", len);
                    277:
                    278:   /* Read the rest of the response in tothe buffer. */
                    279:   buffer_clear(&buffer);
                    280:   while (len > 0)
                    281:     {
                    282:       l = len;
                    283:       if (l > sizeof(buf))
                    284:        l = sizeof(buf);
                    285:       l = read(auth->fd, buf, l);
                    286:       if (l <= 0)
                    287:        {
                    288:          error("Error reading response from authentication socket.");
                    289:          goto error_cleanup;
                    290:        }
                    291:       buffer_append(&buffer, (char *)buf, l);
                    292:       len -= l;
                    293:     }
                    294:
                    295:   /* Get the type of the packet. */
                    296:   buffer_get(&buffer, (char *)buf, 1);
                    297:
                    298:   /* Check for agent failure message. */
                    299:   if (buf[0] == SSH_AGENT_FAILURE)
                    300:     {
                    301:       log("Agent admitted failure to authenticate using the key.");
                    302:       goto error_cleanup;
                    303:     }
                    304:
                    305:   /* Now it must be an authentication response packet. */
                    306:   if (buf[0] != SSH_AGENT_RSA_RESPONSE)
                    307:     fatal("Bad authentication response: %d", buf[0]);
                    308:
                    309:   /* Get the response from the packet.  This will abort with a fatal error
                    310:      if the packet is corrupt. */
                    311:   for (i = 0; i < 16; i++)
                    312:     response[i] = buffer_get_char(&buffer);
                    313:
                    314:   /* The buffer containing the packet is no longer needed. */
                    315:   buffer_free(&buffer);
                    316:
                    317:   /* Correct answer. */
                    318:   return 1;
                    319: }
                    320:
                    321: /* Adds an identity to the authentication server.  This call is not meant to
                    322:    be used by normal applications. */
                    323:
                    324: int ssh_add_identity(AuthenticationConnection *auth,
1.2       provos    325:                     RSA *key, const char *comment)
1.1       deraadt   326: {
                    327:   Buffer buffer;
                    328:   unsigned char buf[8192];
                    329:   int len, l, type;
                    330:
                    331:   /* Format a message to the agent. */
                    332:   buffer_init(&buffer);
                    333:   buffer_put_char(&buffer, SSH_AGENTC_ADD_RSA_IDENTITY);
1.2       provos    334:   buffer_put_int(&buffer, BN_num_bits(key->n));
                    335:   buffer_put_bignum(&buffer, key->n);
                    336:   buffer_put_bignum(&buffer, key->e);
                    337:   buffer_put_bignum(&buffer, key->d);
                    338:   /* To keep within the protocol: p < q for ssh. in SSL p > q */
                    339:   buffer_put_bignum(&buffer, key->iqmp); /* ssh key->u */
                    340:   buffer_put_bignum(&buffer, key->q); /* ssh key->p, SSL key->q */
                    341:   buffer_put_bignum(&buffer, key->p); /* ssh key->q, SSL key->p */
1.1       deraadt   342:   buffer_put_string(&buffer, comment, strlen(comment));
                    343:
                    344:   /* Get the length of the message, and format it in the buffer. */
                    345:   len = buffer_len(&buffer);
                    346:   PUT_32BIT(buf, len);
                    347:
                    348:   /* Send the length and then the packet to the agent. */
                    349:   if (write(auth->fd, buf, 4) != 4 ||
                    350:       write(auth->fd, buffer_ptr(&buffer), buffer_len(&buffer)) !=
                    351:         buffer_len(&buffer))
                    352:     {
                    353:       error("Error writing to authentication socket.");
                    354:     error_cleanup:
                    355:       buffer_free(&buffer);
                    356:       return 0;
                    357:     }
                    358:
                    359:   /* Wait for response from the agent.  First read the length of the
                    360:      response packet. */
                    361:   len = 4;
                    362:   while (len > 0)
                    363:     {
                    364:       l = read(auth->fd, buf + 4 - len, len);
                    365:       if (l <= 0)
                    366:        {
                    367:          error("Error reading response length from authentication socket.");
                    368:          goto error_cleanup;
                    369:        }
                    370:       len -= l;
                    371:     }
                    372:
                    373:   /* Extract the length, and check it for sanity. */
                    374:   len = GET_32BIT(buf);
                    375:   if (len > 256*1024)
                    376:     fatal("Add identity response too long: %d", len);
                    377:
                    378:   /* Read the rest of the response in tothe buffer. */
                    379:   buffer_clear(&buffer);
                    380:   while (len > 0)
                    381:     {
                    382:       l = len;
                    383:       if (l > sizeof(buf))
                    384:        l = sizeof(buf);
                    385:       l = read(auth->fd, buf, l);
                    386:       if (l <= 0)
                    387:        {
                    388:          error("Error reading response from authentication socket.");
                    389:          goto error_cleanup;
                    390:        }
                    391:       buffer_append(&buffer, (char *)buf, l);
                    392:       len -= l;
                    393:     }
                    394:
                    395:   /* Get the type of the packet. */
                    396:   type = buffer_get_char(&buffer);
                    397:   switch (type)
                    398:     {
                    399:     case SSH_AGENT_FAILURE:
                    400:       buffer_free(&buffer);
                    401:       return 0;
                    402:     case SSH_AGENT_SUCCESS:
                    403:       buffer_free(&buffer);
                    404:       return 1;
                    405:     default:
                    406:       fatal("Bad response to add identity from authentication agent: %d",
                    407:            type);
                    408:     }
                    409:   /*NOTREACHED*/
                    410:   return 0;
                    411: }
                    412:
                    413: /* Removes an identity from the authentication server.  This call is not meant
                    414:    to be used by normal applications. */
                    415:
1.2       provos    416: int ssh_remove_identity(AuthenticationConnection *auth, RSA *key)
1.1       deraadt   417: {
                    418:   Buffer buffer;
                    419:   unsigned char buf[8192];
                    420:   int len, l, type;
                    421:
                    422:   /* Format a message to the agent. */
                    423:   buffer_init(&buffer);
                    424:   buffer_put_char(&buffer, SSH_AGENTC_REMOVE_RSA_IDENTITY);
1.2       provos    425:   buffer_put_int(&buffer, BN_num_bits(key->n));
                    426:   buffer_put_bignum(&buffer, key->e);
                    427:   buffer_put_bignum(&buffer, key->n);
1.1       deraadt   428:
                    429:   /* Get the length of the message, and format it in the buffer. */
                    430:   len = buffer_len(&buffer);
                    431:   PUT_32BIT(buf, len);
                    432:
                    433:   /* Send the length and then the packet to the agent. */
                    434:   if (write(auth->fd, buf, 4) != 4 ||
                    435:       write(auth->fd, buffer_ptr(&buffer), buffer_len(&buffer)) !=
                    436:         buffer_len(&buffer))
                    437:     {
                    438:       error("Error writing to authentication socket.");
                    439:     error_cleanup:
                    440:       buffer_free(&buffer);
                    441:       return 0;
                    442:     }
                    443:
                    444:   /* Wait for response from the agent.  First read the length of the
                    445:      response packet. */
                    446:   len = 4;
                    447:   while (len > 0)
                    448:     {
                    449:       l = read(auth->fd, buf + 4 - len, len);
                    450:       if (l <= 0)
                    451:        {
                    452:          error("Error reading response length from authentication socket.");
                    453:          goto error_cleanup;
                    454:        }
                    455:       len -= l;
                    456:     }
                    457:
                    458:   /* Extract the length, and check it for sanity. */
                    459:   len = GET_32BIT(buf);
                    460:   if (len > 256*1024)
                    461:     fatal("Remove identity response too long: %d", len);
                    462:
                    463:   /* Read the rest of the response in tothe buffer. */
                    464:   buffer_clear(&buffer);
                    465:   while (len > 0)
                    466:     {
                    467:       l = len;
                    468:       if (l > sizeof(buf))
                    469:        l = sizeof(buf);
                    470:       l = read(auth->fd, buf, l);
                    471:       if (l <= 0)
                    472:        {
                    473:          error("Error reading response from authentication socket.");
                    474:          goto error_cleanup;
                    475:        }
                    476:       buffer_append(&buffer, (char *)buf, l);
                    477:       len -= l;
                    478:     }
                    479:
                    480:   /* Get the type of the packet. */
                    481:   type = buffer_get_char(&buffer);
                    482:   switch (type)
                    483:     {
                    484:     case SSH_AGENT_FAILURE:
                    485:       buffer_free(&buffer);
                    486:       return 0;
                    487:     case SSH_AGENT_SUCCESS:
                    488:       buffer_free(&buffer);
                    489:       return 1;
                    490:     default:
                    491:       fatal("Bad response to remove identity from authentication agent: %d",
                    492:            type);
                    493:     }
                    494:   /*NOTREACHED*/
                    495:   return 0;
                    496: }
                    497:
                    498: /* Removes all identities from the agent.  This call is not meant
                    499:    to be used by normal applications. */
                    500:
                    501: int ssh_remove_all_identities(AuthenticationConnection *auth)
                    502: {
                    503:   Buffer buffer;
                    504:   unsigned char buf[8192];
                    505:   int len, l, type;
                    506:
                    507:   /* Get the length of the message, and format it in the buffer. */
                    508:   PUT_32BIT(buf, 1);
                    509:   buf[4] = SSH_AGENTC_REMOVE_ALL_RSA_IDENTITIES;
                    510:
                    511:   /* Send the length and then the packet to the agent. */
                    512:   if (write(auth->fd, buf, 5) != 5)
                    513:     {
                    514:       error("Error writing to authentication socket.");
                    515:       return 0;
                    516:     }
                    517:
                    518:   /* Wait for response from the agent.  First read the length of the
                    519:      response packet. */
                    520:   len = 4;
                    521:   while (len > 0)
                    522:     {
                    523:       l = read(auth->fd, buf + 4 - len, len);
                    524:       if (l <= 0)
                    525:        {
                    526:          error("Error reading response length from authentication socket.");
                    527:          return 0;
                    528:        }
                    529:       len -= l;
                    530:     }
                    531:
                    532:   /* Extract the length, and check it for sanity. */
                    533:   len = GET_32BIT(buf);
                    534:   if (len > 256*1024)
                    535:     fatal("Remove identity response too long: %d", len);
                    536:
                    537:   /* Read the rest of the response into the buffer. */
                    538:   buffer_init(&buffer);
                    539:   while (len > 0)
                    540:     {
                    541:       l = len;
                    542:       if (l > sizeof(buf))
                    543:        l = sizeof(buf);
                    544:       l = read(auth->fd, buf, l);
                    545:       if (l <= 0)
                    546:        {
                    547:          error("Error reading response from authentication socket.");
                    548:          buffer_free(&buffer);
                    549:          return 0;
                    550:        }
                    551:       buffer_append(&buffer, (char *)buf, l);
                    552:       len -= l;
                    553:     }
                    554:
                    555:   /* Get the type of the packet. */
                    556:   type = buffer_get_char(&buffer);
                    557:   switch (type)
                    558:     {
                    559:     case SSH_AGENT_FAILURE:
                    560:       buffer_free(&buffer);
                    561:       return 0;
                    562:     case SSH_AGENT_SUCCESS:
                    563:       buffer_free(&buffer);
                    564:       return 1;
                    565:     default:
                    566:       fatal("Bad response to remove identity from authentication agent: %d",
                    567:            type);
                    568:     }
                    569:   /*NOTREACHED*/
                    570:   return 0;
                    571: }