Blame src/pki_gcrypt.c

Packit Service 31306d
/*
Packit Service 31306d
 * pki_gcrypt.c private and public key handling using gcrypt.
Packit Service 31306d
 *
Packit Service 31306d
 * This file is part of the SSH Library
Packit Service 31306d
 *
Packit Service 31306d
 * Copyright (c) 2003-2009 Aris Adamantiadis
Packit Service 31306d
 * Copyright (c) 2009-2011 Andreas Schneider <asn@cryptomilk.org>
Packit Service 31306d
 * Copyright (C) 2016 g10 Code GmbH
Packit Service 31306d
 *
Packit Service 31306d
 * The SSH Library is free software; you can redistribute it and/or modify
Packit Service 31306d
 * it under the terms of the GNU Lesser General Public License as published by
Packit Service 31306d
 * the Free Software Foundation; either version 2.1 of the License, or (at your
Packit Service 31306d
 * option) any later version.
Packit Service 31306d
 *
Packit Service 31306d
 * The SSH Library is distributed in the hope that it will be useful, but
Packit Service 31306d
 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
Packit Service 31306d
 * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public
Packit Service 31306d
 * License for more details.
Packit Service 31306d
 *
Packit Service 31306d
 * You should have received a copy of the GNU Lesser General Public License
Packit Service 31306d
 * along with the SSH Library; see the file COPYING.  If not, write to
Packit Service 31306d
 * the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
Packit Service 31306d
 * MA 02111-1307, USA.
Packit Service 31306d
 */
Packit Service 31306d
Packit Service 31306d
#include "config.h"
Packit Service 31306d
Packit Service 31306d
#ifdef HAVE_LIBGCRYPT
Packit Service 31306d
Packit Service 31306d
#include <assert.h>
Packit Service 31306d
#include <stdbool.h>
Packit Service 31306d
#include <string.h>
Packit Service 31306d
#include <stdlib.h>
Packit Service 31306d
#include <gcrypt.h>
Packit Service 31306d
#include <stdio.h>
Packit Service 31306d
Packit Service 31306d
#include "libssh/priv.h"
Packit Service 31306d
#include "libssh/buffer.h"
Packit Service 31306d
#include "libssh/session.h"
Packit Service 31306d
#include "libssh/wrapper.h"
Packit Service 31306d
#include "libssh/misc.h"
Packit Service 31306d
#include "libssh/pki.h"
Packit Service 31306d
#include "libssh/pki_priv.h"
Packit Service 31306d
Packit Service 31306d
#define MAXLINESIZE 80
Packit Service 31306d
#define RSA_HEADER_BEGIN "-----BEGIN RSA PRIVATE KEY-----"
Packit Service 31306d
#define RSA_HEADER_END "-----END RSA PRIVATE KEY-----"
Packit Service 31306d
#define DSA_HEADER_BEGIN "-----BEGIN DSA PRIVATE KEY-----"
Packit Service 31306d
#define DSA_HEADER_END "-----END DSA PRIVATE KEY-----"
Packit Service 31306d
#define ECDSA_HEADER_BEGIN "-----BEGIN EC PRIVATE KEY-----"
Packit Service 31306d
#define ECDSA_HEADER_END "-----END EC PRIVATE KEY-----"
Packit Service 31306d
Packit Service 31306d
#define MAX_KEY_SIZE 32
Packit Service 31306d
#define MAX_PASSPHRASE_SIZE 1024
Packit Service 31306d
#define ASN1_INTEGER 2
Packit Service 31306d
#define ASN1_BIT_STRING 3
Packit Service 31306d
#define ASN1_OCTET_STRING 4
Packit Service 31306d
#define ASN1_OBJECT_IDENTIFIER 6
Packit Service 31306d
#define ASN1_SEQUENCE 48
Packit Service 31306d
#define PKCS5_SALT_LEN 8
Packit Service 31306d
Packit Service 31306d
static int load_iv(const char *header, unsigned char *iv, int iv_len) {
Packit Service 31306d
  int i;
Packit Service 31306d
  int j;
Packit Service 31306d
  int k;
Packit Service 31306d
Packit Service 31306d
  memset(iv, 0, iv_len);
Packit Service 31306d
  for (i = 0; i < iv_len; i++) {
Packit Service 31306d
    if ((header[2*i] >= '0') && (header[2*i] <= '9'))
Packit Service 31306d
      j = header[2*i] - '0';
Packit Service 31306d
    else if ((header[2*i] >= 'A') && (header[2*i] <= 'F'))
Packit Service 31306d
      j = header[2*i] - 'A' + 10;
Packit Service 31306d
    else if ((header[2*i] >= 'a') && (header[2*i] <= 'f'))
Packit Service 31306d
      j = header[2*i] - 'a' + 10;
Packit Service 31306d
    else
Packit Service 31306d
      return -1;
Packit Service 31306d
    if ((header[2*i+1] >= '0') && (header[2*i+1] <= '9'))
Packit Service 31306d
      k = header[2*i+1] - '0';
Packit Service 31306d
    else if ((header[2*i+1] >= 'A') && (header[2*i+1] <= 'F'))
Packit Service 31306d
      k = header[2*i+1] - 'A' + 10;
Packit Service 31306d
    else if ((header[2*i+1] >= 'a') && (header[2*i+1] <= 'f'))
Packit Service 31306d
      k = header[2*i+1] - 'a' + 10;
Packit Service 31306d
    else
Packit Service 31306d
      return -1;
Packit Service 31306d
    iv[i] = (j << 4) + k;
Packit Service 31306d
  }
Packit Service 31306d
  return 0;
Packit Service 31306d
}
Packit Service 31306d
Packit Service 31306d
static uint32_t char_to_u32(unsigned char *data, uint32_t size) {
Packit Service 31306d
  uint32_t ret;
Packit Service 31306d
  uint32_t i;
Packit Service 31306d
Packit Service 31306d
  for (i = 0, ret = 0; i < size; ret = ret << 8, ret += data[i++])
Packit Service 31306d
    ;
Packit Service 31306d
  return ret;
Packit Service 31306d
}
Packit Service 31306d
Packit Service 31306d
static uint32_t asn1_get_len(ssh_buffer buffer) {
Packit Service 31306d
  uint32_t len;
Packit Service 31306d
  unsigned char tmp[4];
Packit Service 31306d
Packit Service 31306d
  if (ssh_buffer_get_data(buffer,tmp,1) == 0) {
Packit Service 31306d
    return 0;
Packit Service 31306d
  }
Packit Service 31306d
Packit Service 31306d
  if (tmp[0] > 127) {
Packit Service 31306d
    len = tmp[0] & 127;
Packit Service 31306d
    if (len > 4) {
Packit Service 31306d
      return 0; /* Length doesn't fit in u32. Can this really happen? */
Packit Service 31306d
    }
Packit Service 31306d
    if (ssh_buffer_get_data(buffer,tmp,len) == 0) {
Packit Service 31306d
      return 0;
Packit Service 31306d
    }
Packit Service 31306d
    len = char_to_u32(tmp, len);
Packit Service 31306d
  } else {
Packit Service 31306d
    len = char_to_u32(tmp, 1);
Packit Service 31306d
  }
Packit Service 31306d
Packit Service 31306d
  return len;
Packit Service 31306d
}
Packit Service 31306d
Packit Service 31306d
static ssh_string asn1_get(ssh_buffer buffer, unsigned char want) {
Packit Service 31306d
  ssh_string str;
Packit Service 31306d
  unsigned char type;
Packit Service 31306d
  uint32_t size;
Packit Service 31306d
Packit Service 31306d
  if (ssh_buffer_get_data(buffer, &type, 1) == 0 || type != want) {
Packit Service 31306d
    return NULL;
Packit Service 31306d
  }
Packit Service 31306d
  size = asn1_get_len(buffer);
Packit Service 31306d
  if (size == 0) {
Packit Service 31306d
    return NULL;
Packit Service 31306d
  }
Packit Service 31306d
Packit Service 31306d
  str = ssh_string_new(size);
Packit Service 31306d
  if (str == NULL) {
Packit Service 31306d
    return NULL;
Packit Service 31306d
  }
Packit Service 31306d
Packit Service 31306d
  if (ssh_buffer_get_data(buffer, ssh_string_data(str), size) == 0) {
Packit Service 31306d
    SSH_STRING_FREE(str);
Packit Service 31306d
    return NULL;
Packit Service 31306d
  }
Packit Service 31306d
Packit Service 31306d
  return str;
Packit Service 31306d
}
Packit Service 31306d
Packit Service 31306d
static ssh_string asn1_get_int(ssh_buffer buffer) {
Packit Service 31306d
  return asn1_get(buffer, ASN1_INTEGER);
Packit Service 31306d
}
Packit Service 31306d
Packit Service 31306d
static ssh_string asn1_get_bit_string(ssh_buffer buffer)
Packit Service 31306d
{
Packit Service 31306d
    ssh_string str;
Packit Service 31306d
    unsigned char type;
Packit Service 31306d
    uint32_t size;
Packit Service 31306d
    unsigned char unused, last, *p;
Packit Service 31306d
    uint32_t len;
Packit Service 31306d
Packit Service 31306d
    len = ssh_buffer_get_data(buffer, &type, 1);
Packit Service 31306d
    if (len == 0 || type != ASN1_BIT_STRING) {
Packit Service 31306d
        return NULL;
Packit Service 31306d
    }
Packit Service 31306d
    size = asn1_get_len(buffer);
Packit Service 31306d
    if (size == 0) {
Packit Service 31306d
        return NULL;
Packit Service 31306d
    }
Packit Service 31306d
Packit Service 31306d
    /* The first octet encodes the number of unused bits.  */
Packit Service 31306d
    size -= 1;
Packit Service 31306d
Packit Service 31306d
    str = ssh_string_new(size);
Packit Service 31306d
    if (str == NULL) {
Packit Service 31306d
        return NULL;
Packit Service 31306d
    }
Packit Service 31306d
Packit Service 31306d
    len = ssh_buffer_get_data(buffer, &unused, 1);
Packit Service 31306d
    if (len == 0) {
Packit Service 31306d
        SSH_STRING_FREE(str);
Packit Service 31306d
        return NULL;
Packit Service 31306d
    }
Packit Service 31306d
Packit Service 31306d
    if (unused == 0) {
Packit Service 31306d
        len = ssh_buffer_get_data(buffer, ssh_string_data(str), size);
Packit Service 31306d
        if (len == 0) {
Packit Service 31306d
            SSH_STRING_FREE(str);
Packit Service 31306d
            return NULL;
Packit Service 31306d
        }
Packit Service 31306d
        return str;
Packit Service 31306d
    }
Packit Service 31306d
Packit Service 31306d
    /* The bit string is padded at the end, we must shift the whole
Packit Service 31306d
       string by UNUSED bits.  */
Packit Service 31306d
    for (p = ssh_string_data(str), last = 0; size; size--, p++) {
Packit Service 31306d
        unsigned char c;
Packit Service 31306d
Packit Service 31306d
        len = ssh_buffer_get_data(buffer, &c, 1);
Packit Service 31306d
        if (len == 0) {
Packit Service 31306d
            SSH_STRING_FREE(str);
Packit Service 31306d
            return NULL;
Packit Service 31306d
        }
Packit Service 31306d
        *p = last | (c >> unused);
Packit Service 31306d
        last = c << (8 - unused);
Packit Service 31306d
    }
Packit Service 31306d
Packit Service 31306d
    return str;
Packit Service 31306d
}
Packit Service 31306d
Packit Service 31306d
static int asn1_check_sequence(ssh_buffer buffer) {
Packit Service 31306d
  unsigned char *j = NULL;
Packit Service 31306d
  unsigned char tmp;
Packit Service 31306d
  int i;
Packit Service 31306d
  uint32_t size;
Packit Service 31306d
  uint32_t padding;
Packit Service 31306d
Packit Service 31306d
  if (ssh_buffer_get_data(buffer, &tmp, 1) == 0 || tmp != ASN1_SEQUENCE) {
Packit Service 31306d
    return 0;
Packit Service 31306d
  }
Packit Service 31306d
Packit Service 31306d
  size = asn1_get_len(buffer);
Packit Service 31306d
  if ((padding = ssh_buffer_get_len(buffer) - size) > 0) {
Packit Service 31306d
    for (i = ssh_buffer_get_len(buffer) - size,
Packit Service 31306d
         j = (unsigned char*)ssh_buffer_get(buffer) + size;
Packit Service 31306d
         i;
Packit Service 31306d
         i--, j++)
Packit Service 31306d
    {
Packit Service 31306d
      if (*j != padding) {                   /* padding is allowed */
Packit Service 31306d
        return 0;                            /* but nothing else */
Packit Service 31306d
      }
Packit Service 31306d
    }
Packit Service 31306d
  }
Packit Service 31306d
Packit Service 31306d
  return 1;
Packit Service 31306d
}
Packit Service 31306d
Packit Service 31306d
static int asn1_check_tag(ssh_buffer buffer, unsigned char tag) {
Packit Service 31306d
    unsigned char tmp;
Packit Service 31306d
    uint32_t len;
Packit Service 31306d
Packit Service 31306d
    len = ssh_buffer_get_data(buffer, &tmp, 1);
Packit Service 31306d
    if (len == 0 || tmp != tag) {
Packit Service 31306d
        return 0;
Packit Service 31306d
    }
Packit Service 31306d
Packit Service 31306d
    (void) asn1_get_len(buffer);
Packit Service 31306d
    return 1;
Packit Service 31306d
}
Packit Service 31306d
Packit Service 31306d
static int passphrase_to_key(char *data, unsigned int datalen,
Packit Service 31306d
    unsigned char *salt, unsigned char *key, unsigned int keylen) {
Packit Service 31306d
  MD5CTX md;
Packit Service 31306d
  unsigned char digest[MD5_DIGEST_LEN] = {0};
Packit Service 31306d
  unsigned int i;
Packit Service 31306d
  unsigned int j;
Packit Service 31306d
  unsigned int md_not_empty;
Packit Service 31306d
Packit Service 31306d
  for (j = 0, md_not_empty = 0; j < keylen; ) {
Packit Service 31306d
    md = md5_init();
Packit Service 31306d
    if (md == NULL) {
Packit Service 31306d
      return -1;
Packit Service 31306d
    }
Packit Service 31306d
Packit Service 31306d
    if (md_not_empty) {
Packit Service 31306d
      md5_update(md, digest, MD5_DIGEST_LEN);
Packit Service 31306d
    } else {
Packit Service 31306d
      md_not_empty = 1;
Packit Service 31306d
    }
Packit Service 31306d
Packit Service 31306d
    md5_update(md, data, datalen);
Packit Service 31306d
    if (salt) {
Packit Service 31306d
      md5_update(md, salt, PKCS5_SALT_LEN);
Packit Service 31306d
    }
Packit Service 31306d
    md5_final(digest, md);
Packit Service 31306d
Packit Service 31306d
    for (i = 0; j < keylen && i < MD5_DIGEST_LEN; j++, i++) {
Packit Service 31306d
      if (key) {
Packit Service 31306d
        key[j] = digest[i];
Packit Service 31306d
      }
Packit Service 31306d
    }
Packit Service 31306d
  }
Packit Service 31306d
Packit Service 31306d
  return 0;
Packit Service 31306d
}
Packit Service 31306d
Packit Service 31306d
static int privatekey_decrypt(int algo, int mode, unsigned int key_len,
Packit Service 31306d
                       unsigned char *iv, unsigned int iv_len,
Packit Service 31306d
                       ssh_buffer data, ssh_auth_callback cb,
Packit Service 31306d
                       void *userdata,
Packit Service 31306d
                       const char *desc)
Packit Service 31306d
{
Packit Service 31306d
  char passphrase[MAX_PASSPHRASE_SIZE] = {0};
Packit Service 31306d
  unsigned char key[MAX_KEY_SIZE] = {0};
Packit Service 31306d
  unsigned char *tmp = NULL;
Packit Service 31306d
  gcry_cipher_hd_t cipher;
Packit Service 31306d
  int rc = -1;
Packit Service 31306d
Packit Service 31306d
  if (!algo) {
Packit Service 31306d
    return -1;
Packit Service 31306d
  }
Packit Service 31306d
Packit Service 31306d
  if (cb) {
Packit Service 31306d
    rc = (*cb)(desc, passphrase, MAX_PASSPHRASE_SIZE, 0, 0, userdata);
Packit Service 31306d
    if (rc < 0) {
Packit Service 31306d
      return -1;
Packit Service 31306d
    }
Packit Service 31306d
  } else if (cb == NULL && userdata != NULL) {
Packit Service 31306d
    snprintf(passphrase, MAX_PASSPHRASE_SIZE, "%s", (char *) userdata);
Packit Service 31306d
  }
Packit Service 31306d
Packit Service 31306d
  if (passphrase_to_key(passphrase, strlen(passphrase), iv, key, key_len) < 0) {
Packit Service 31306d
    return -1;
Packit Service 31306d
  }
Packit Service 31306d
Packit Service 31306d
  if (gcry_cipher_open(&cipher, algo, mode, 0)
Packit Service 31306d
      || gcry_cipher_setkey(cipher, key, key_len)
Packit Service 31306d
      || gcry_cipher_setiv(cipher, iv, iv_len)
Packit Service 31306d
      || (tmp = calloc(ssh_buffer_get_len(data), sizeof(unsigned char))) == NULL
Packit Service 31306d
      || gcry_cipher_decrypt(cipher, tmp, ssh_buffer_get_len(data),
Packit Service 31306d
                       ssh_buffer_get(data), ssh_buffer_get_len(data))) {
Packit Service 31306d
    gcry_cipher_close(cipher);
Packit Service 31306d
    return -1;
Packit Service 31306d
  }
Packit Service 31306d
Packit Service 31306d
  memcpy(ssh_buffer_get(data), tmp, ssh_buffer_get_len(data));
Packit Service 31306d
Packit Service 31306d
  SAFE_FREE(tmp);
Packit Service 31306d
  gcry_cipher_close(cipher);
Packit Service 31306d
Packit Service 31306d
  return 0;
Packit Service 31306d
}
Packit Service 31306d
Packit Service 31306d
static int privatekey_dek_header(const char *header, unsigned int header_len,
Packit Service 31306d
    int *algo, int *mode, unsigned int *key_len, unsigned char **iv,
Packit Service 31306d
    unsigned int *iv_len) {
Packit Service 31306d
  unsigned int iv_pos;
Packit Service 31306d
Packit Service 31306d
  if (header_len > 13 && !strncmp("DES-EDE3-CBC", header, 12))
Packit Service 31306d
  {
Packit Service 31306d
    *algo = GCRY_CIPHER_3DES;
Packit Service 31306d
    iv_pos = 13;
Packit Service 31306d
    *mode = GCRY_CIPHER_MODE_CBC;
Packit Service 31306d
    *key_len = 24;
Packit Service 31306d
    *iv_len = 8;
Packit Service 31306d
  }
Packit Service 31306d
  else if (header_len > 8 && !strncmp("DES-CBC", header, 7))
Packit Service 31306d
  {
Packit Service 31306d
    *algo = GCRY_CIPHER_DES;
Packit Service 31306d
    iv_pos = 8;
Packit Service 31306d
    *mode = GCRY_CIPHER_MODE_CBC;
Packit Service 31306d
    *key_len = 8;
Packit Service 31306d
    *iv_len = 8;
Packit Service 31306d
  }
Packit Service 31306d
  else if (header_len > 12 && !strncmp("AES-128-CBC", header, 11))
Packit Service 31306d
  {
Packit Service 31306d
    *algo = GCRY_CIPHER_AES128;
Packit Service 31306d
    iv_pos = 12;
Packit Service 31306d
    *mode = GCRY_CIPHER_MODE_CBC;
Packit Service 31306d
    *key_len = 16;
Packit Service 31306d
    *iv_len = 16;
Packit Service 31306d
  }
Packit Service 31306d
  else if (header_len > 12 && !strncmp("AES-192-CBC", header, 11))
Packit Service 31306d
  {
Packit Service 31306d
    *algo = GCRY_CIPHER_AES192;
Packit Service 31306d
    iv_pos = 12;
Packit Service 31306d
    *mode = GCRY_CIPHER_MODE_CBC;
Packit Service 31306d
    *key_len = 24;
Packit Service 31306d
    *iv_len = 16;
Packit Service 31306d
  }
Packit Service 31306d
  else if (header_len > 12 && !strncmp("AES-256-CBC", header, 11))
Packit Service 31306d
  {
Packit Service 31306d
    *algo = GCRY_CIPHER_AES256;
Packit Service 31306d
    iv_pos = 12;
Packit Service 31306d
    *mode = GCRY_CIPHER_MODE_CBC;
Packit Service 31306d
    *key_len = 32;
Packit Service 31306d
    *iv_len = 16;
Packit Service 31306d
  } else {
Packit Service 31306d
    return -1;
Packit Service 31306d
  }
Packit Service 31306d
Packit Service 31306d
  *iv = malloc(*iv_len);
Packit Service 31306d
  if (*iv == NULL) {
Packit Service 31306d
    return -1;
Packit Service 31306d
  }
Packit Service 31306d
Packit Service 31306d
  return load_iv(header + iv_pos, *iv, *iv_len);
Packit Service 31306d
}
Packit Service 31306d
Packit Service 31306d
#define get_next_line(p, len) {                                         \
Packit Service 31306d
        while(p[len] == '\n' || p[len] == '\r') /* skip empty lines */  \
Packit Service 31306d
            len++;                                                      \
Packit Service 31306d
        if(p[len] == '\0')    /* EOL */                                 \
Packit Service 31306d
            eol = true;                                                 \
Packit Service 31306d
        else                  /* calculate length */                    \
Packit Service 31306d
            for(p += len, len = 0; p[len] && p[len] != '\n'             \
Packit Service 31306d
                                          && p[len] != '\r'; len++);    \
Packit Service 31306d
    }
Packit Service 31306d
Packit Service 31306d
static ssh_buffer privatekey_string_to_buffer(const char *pkey, int type,
Packit Service 31306d
                ssh_auth_callback cb, void *userdata, const char *desc) {
Packit Service 31306d
    ssh_buffer buffer = NULL;
Packit Service 31306d
    ssh_buffer out = NULL;
Packit Service 31306d
    const char *p;
Packit Service 31306d
    unsigned char *iv = NULL;
Packit Service 31306d
    const char *header_begin;
Packit Service 31306d
    const char *header_end;
Packit Service 31306d
    unsigned int header_begin_size;
Packit Service 31306d
    unsigned int header_end_size;
Packit Service 31306d
    unsigned int key_len = 0;
Packit Service 31306d
    unsigned int iv_len = 0;
Packit Service 31306d
    int algo = 0;
Packit Service 31306d
    int mode = 0;
Packit Service 31306d
    bool eol = false;
Packit Service 31306d
    size_t len;
Packit Service 31306d
Packit Service 31306d
    buffer = ssh_buffer_new();
Packit Service 31306d
    if (buffer == NULL) {
Packit Service 31306d
        return NULL;
Packit Service 31306d
    }
Packit Service 31306d
Packit Service 31306d
    switch(type) {
Packit Service 31306d
        case SSH_KEYTYPE_DSS:
Packit Service 31306d
            header_begin = DSA_HEADER_BEGIN;
Packit Service 31306d
            header_end = DSA_HEADER_END;
Packit Service 31306d
            break;
Packit Service 31306d
        case SSH_KEYTYPE_RSA:
Packit Service 31306d
            header_begin = RSA_HEADER_BEGIN;
Packit Service 31306d
            header_end = RSA_HEADER_END;
Packit Service 31306d
            break;
Packit Service 31306d
        case SSH_KEYTYPE_ECDSA_P256:
Packit Service 31306d
        case SSH_KEYTYPE_ECDSA_P384:
Packit Service 31306d
        case SSH_KEYTYPE_ECDSA_P521:
Packit Service 31306d
            header_begin = ECDSA_HEADER_BEGIN;
Packit Service 31306d
            header_end = ECDSA_HEADER_END;
Packit Service 31306d
            break;
Packit Service 31306d
        default:
Packit Service 31306d
            SSH_BUFFER_FREE(buffer);
Packit Service 31306d
            return NULL;
Packit Service 31306d
    }
Packit Service 31306d
Packit Service 31306d
    header_begin_size = strlen(header_begin);
Packit Service 31306d
    header_end_size = strlen(header_end);
Packit Service 31306d
Packit Service 31306d
    p = pkey;
Packit Service 31306d
    len = 0;
Packit Service 31306d
    get_next_line(p, len);
Packit Service 31306d
Packit Service 31306d
    while(!eol && strncmp(p, header_begin, header_begin_size)) {
Packit Service 31306d
        /* skip line */
Packit Service 31306d
        get_next_line(p, len);
Packit Service 31306d
    }
Packit Service 31306d
    if (eol) {
Packit Service 31306d
        SSH_BUFFER_FREE(buffer);
Packit Service 31306d
        return NULL;
Packit Service 31306d
    }
Packit Service 31306d
Packit Service 31306d
    /* skip header line */
Packit Service 31306d
    get_next_line(p, len);
Packit Service 31306d
    if (eol) {
Packit Service 31306d
        SSH_BUFFER_FREE(buffer);
Packit Service 31306d
        return NULL;
Packit Service 31306d
    }
Packit Service 31306d
Packit Service 31306d
    if (len > 11 && strncmp("Proc-Type: 4,ENCRYPTED", p, 11) == 0) {
Packit Service 31306d
        /* skip line */
Packit Service 31306d
        get_next_line(p, len);
Packit Service 31306d
        if (eol) {
Packit Service 31306d
            SSH_BUFFER_FREE(buffer);
Packit Service 31306d
            return NULL;
Packit Service 31306d
        }
Packit Service 31306d
Packit Service 31306d
        if (len > 10 && strncmp("DEK-Info: ", p, 10) == 0) {
Packit Service 31306d
            p += 10;
Packit Service 31306d
            len = 0;
Packit Service 31306d
            get_next_line(p, len);
Packit Service 31306d
            if (eol) {
Packit Service 31306d
                SSH_BUFFER_FREE(buffer);
Packit Service 31306d
                return NULL;
Packit Service 31306d
            }
Packit Service 31306d
            if (privatekey_dek_header(p, len, &algo, &mode, &key_len,
Packit Service 31306d
                        &iv, &iv_len) < 0) {
Packit Service 31306d
                SSH_BUFFER_FREE(buffer);
Packit Service 31306d
                SAFE_FREE(iv);
Packit Service 31306d
                return NULL;
Packit Service 31306d
            }
Packit Service 31306d
        } else {
Packit Service 31306d
            SSH_BUFFER_FREE(buffer);
Packit Service 31306d
            SAFE_FREE(iv);
Packit Service 31306d
            return NULL;
Packit Service 31306d
        }
Packit Service 31306d
    } else {
Packit Service 31306d
        if(len > 0) {
Packit Service 31306d
            if (ssh_buffer_add_data(buffer, p, len) < 0) {
Packit Service 31306d
                SSH_BUFFER_FREE(buffer);
Packit Service 31306d
                SAFE_FREE(iv);
Packit Service 31306d
                return NULL;
Packit Service 31306d
            }
Packit Service 31306d
        }
Packit Service 31306d
    }
Packit Service 31306d
Packit Service 31306d
    get_next_line(p, len);
Packit Service 31306d
    while(!eol && strncmp(p, header_end, header_end_size) != 0) {
Packit Service 31306d
        if (ssh_buffer_add_data(buffer, p, len) < 0) {
Packit Service 31306d
            SSH_BUFFER_FREE(buffer);
Packit Service 31306d
            SAFE_FREE(iv);
Packit Service 31306d
            return NULL;
Packit Service 31306d
        }
Packit Service 31306d
        get_next_line(p, len);
Packit Service 31306d
    }
Packit Service 31306d
Packit Service 31306d
    if (eol || strncmp(p, header_end, header_end_size) != 0) {
Packit Service 31306d
        SSH_BUFFER_FREE(buffer);
Packit Service 31306d
        SAFE_FREE(iv);
Packit Service 31306d
        return NULL;
Packit Service 31306d
    }
Packit Service 31306d
Packit Service 31306d
    if (ssh_buffer_add_data(buffer, "\0", 1) < 0) {
Packit Service 31306d
        SSH_BUFFER_FREE(buffer);
Packit Service 31306d
        SAFE_FREE(iv);
Packit Service 31306d
        return NULL;
Packit Service 31306d
    }
Packit Service 31306d
Packit Service 31306d
    out = base64_to_bin(ssh_buffer_get(buffer));
Packit Service 31306d
    SSH_BUFFER_FREE(buffer);
Packit Service 31306d
    if (out == NULL) {
Packit Service 31306d
        SAFE_FREE(iv);
Packit Service 31306d
        return NULL;
Packit Service 31306d
    }
Packit Service 31306d
Packit Service 31306d
    if (algo) {
Packit Service 31306d
        if (privatekey_decrypt(algo, mode, key_len, iv, iv_len, out,
Packit Service 31306d
                    cb, userdata, desc) < 0) {
Packit Service 31306d
            SSH_BUFFER_FREE(out);
Packit Service 31306d
            SAFE_FREE(iv);
Packit Service 31306d
            return NULL;
Packit Service 31306d
        }
Packit Service 31306d
    }
Packit Service 31306d
    SAFE_FREE(iv);
Packit Service 31306d
Packit Service 31306d
    return out;
Packit Service 31306d
}
Packit Service 31306d
Packit Service 31306d
static int b64decode_rsa_privatekey(const char *pkey, gcry_sexp_t *r,
Packit Service 31306d
    ssh_auth_callback cb, void *userdata, const char *desc) {
Packit Service 31306d
  const unsigned char *data;
Packit Service 31306d
  ssh_string n = NULL;
Packit Service 31306d
  ssh_string e = NULL;
Packit Service 31306d
  ssh_string d = NULL;
Packit Service 31306d
  ssh_string p = NULL;
Packit Service 31306d
  ssh_string q = NULL;
Packit Service 31306d
  ssh_string unused1 = NULL;
Packit Service 31306d
  ssh_string unused2 = NULL;
Packit Service 31306d
  ssh_string u = NULL;
Packit Service 31306d
  ssh_string v = NULL;
Packit Service 31306d
  ssh_buffer buffer = NULL;
Packit Service 31306d
  int rc = 1;
Packit Service 31306d
Packit Service 31306d
  buffer = privatekey_string_to_buffer(pkey, SSH_KEYTYPE_RSA, cb, userdata, desc);
Packit Service 31306d
  if (buffer == NULL) {
Packit Service 31306d
    return 0;
Packit Service 31306d
  }
Packit Service 31306d
Packit Service 31306d
  if (!asn1_check_sequence(buffer)) {
Packit Service 31306d
    SSH_BUFFER_FREE(buffer);
Packit Service 31306d
    return 0;
Packit Service 31306d
  }
Packit Service 31306d
Packit Service 31306d
  v = asn1_get_int(buffer);
Packit Service 31306d
  if (v == NULL) {
Packit Service 31306d
    SSH_BUFFER_FREE(buffer);
Packit Service 31306d
    return 0;
Packit Service 31306d
  }
Packit Service 31306d
Packit Service 31306d
  data = ssh_string_data(v);
Packit Service 31306d
  if (ssh_string_len(v) != 1 || data[0] != 0) {
Packit Service 31306d
    SSH_STRING_FREE(v);
Packit Service 31306d
    SSH_BUFFER_FREE(buffer);
Packit Service 31306d
    return 0;
Packit Service 31306d
  }
Packit Service 31306d
Packit Service 31306d
  n = asn1_get_int(buffer);
Packit Service 31306d
  e = asn1_get_int(buffer);
Packit Service 31306d
  d = asn1_get_int(buffer);
Packit Service 31306d
  q = asn1_get_int(buffer);
Packit Service 31306d
  p = asn1_get_int(buffer);
Packit Service 31306d
  unused1 = asn1_get_int(buffer);
Packit Service 31306d
  unused2 = asn1_get_int(buffer);
Packit Service 31306d
  u = asn1_get_int(buffer);
Packit Service 31306d
Packit Service 31306d
  SSH_BUFFER_FREE(buffer);
Packit Service 31306d
Packit Service 31306d
  if (n == NULL || e == NULL || d == NULL || p == NULL || q == NULL ||
Packit Service 31306d
      unused1 == NULL || unused2 == NULL|| u == NULL) {
Packit Service 31306d
    rc = 0;
Packit Service 31306d
    goto error;
Packit Service 31306d
  }
Packit Service 31306d
Packit Service 31306d
  if (gcry_sexp_build(r, NULL,
Packit Service 31306d
      "(private-key(rsa(n %b)(e %b)(d %b)(p %b)(q %b)(u %b)))",
Packit Service 31306d
      ssh_string_len(n), ssh_string_data(n),
Packit Service 31306d
      ssh_string_len(e), ssh_string_data(e),
Packit Service 31306d
      ssh_string_len(d), ssh_string_data(d),
Packit Service 31306d
      ssh_string_len(p), ssh_string_data(p),
Packit Service 31306d
      ssh_string_len(q), ssh_string_data(q),
Packit Service 31306d
      ssh_string_len(u), ssh_string_data(u))) {
Packit Service 31306d
    rc = 0;
Packit Service 31306d
  }
Packit Service 31306d
Packit Service 31306d
error:
Packit Service 31306d
  ssh_string_burn(n);
Packit Service 31306d
  SSH_STRING_FREE(n);
Packit Service 31306d
  ssh_string_burn(e);
Packit Service 31306d
  SSH_STRING_FREE(e);
Packit Service 31306d
  ssh_string_burn(d);
Packit Service 31306d
  SSH_STRING_FREE(d);
Packit Service 31306d
  ssh_string_burn(p);
Packit Service 31306d
  SSH_STRING_FREE(p);
Packit Service 31306d
  ssh_string_burn(q);
Packit Service 31306d
  SSH_STRING_FREE(q);
Packit Service 31306d
  SSH_STRING_FREE(unused1);
Packit Service 31306d
  SSH_STRING_FREE(unused2);
Packit Service 31306d
  ssh_string_burn(u);
Packit Service 31306d
  SSH_STRING_FREE(u);
Packit Service 31306d
  SSH_STRING_FREE(v);
Packit Service 31306d
Packit Service 31306d
  return rc;
Packit Service 31306d
}
Packit Service 31306d
Packit Service 31306d
static int b64decode_dsa_privatekey(const char *pkey, gcry_sexp_t *r, ssh_auth_callback cb,
Packit Service 31306d
    void *userdata, const char *desc) {
Packit Service 31306d
  const unsigned char *data;
Packit Service 31306d
  ssh_buffer buffer = NULL;
Packit Service 31306d
  ssh_string p = NULL;
Packit Service 31306d
  ssh_string q = NULL;
Packit Service 31306d
  ssh_string g = NULL;
Packit Service 31306d
  ssh_string y = NULL;
Packit Service 31306d
  ssh_string x = NULL;
Packit Service 31306d
  ssh_string v = NULL;
Packit Service 31306d
  int rc = 1;
Packit Service 31306d
Packit Service 31306d
  buffer = privatekey_string_to_buffer(pkey, SSH_KEYTYPE_DSS, cb, userdata, desc);
Packit Service 31306d
  if (buffer == NULL) {
Packit Service 31306d
    return 0;
Packit Service 31306d
  }
Packit Service 31306d
Packit Service 31306d
  if (!asn1_check_sequence(buffer)) {
Packit Service 31306d
    SSH_BUFFER_FREE(buffer);
Packit Service 31306d
    return 0;
Packit Service 31306d
  }
Packit Service 31306d
Packit Service 31306d
  v = asn1_get_int(buffer);
Packit Service 31306d
  if (v == NULL) {
Packit Service 31306d
    SSH_BUFFER_FREE(buffer);
Packit Service 31306d
    return 0;
Packit Service 31306d
  }
Packit Service 31306d
Packit Service 31306d
  data = ssh_string_data(v);
Packit Service 31306d
  if (ssh_string_len(v) != 1 || data[0] != 0) {
Packit Service 31306d
    SSH_STRING_FREE(v);
Packit Service 31306d
    SSH_BUFFER_FREE(buffer);
Packit Service 31306d
    return 0;
Packit Service 31306d
  }
Packit Service 31306d
Packit Service 31306d
  p = asn1_get_int(buffer);
Packit Service 31306d
  q = asn1_get_int(buffer);
Packit Service 31306d
  g = asn1_get_int(buffer);
Packit Service 31306d
  y = asn1_get_int(buffer);
Packit Service 31306d
  x = asn1_get_int(buffer);
Packit Service 31306d
  SSH_BUFFER_FREE(buffer);
Packit Service 31306d
Packit Service 31306d
  if (p == NULL || q == NULL || g == NULL || y == NULL || x == NULL) {
Packit Service 31306d
    rc = 0;
Packit Service 31306d
    goto error;
Packit Service 31306d
  }
Packit Service 31306d
Packit Service 31306d
  if (gcry_sexp_build(r, NULL,
Packit Service 31306d
        "(private-key(dsa(p %b)(q %b)(g %b)(y %b)(x %b)))",
Packit Service 31306d
        ssh_string_len(p), ssh_string_data(p),
Packit Service 31306d
        ssh_string_len(q), ssh_string_data(q),
Packit Service 31306d
        ssh_string_len(g), ssh_string_data(g),
Packit Service 31306d
        ssh_string_len(y), ssh_string_data(y),
Packit Service 31306d
        ssh_string_len(x), ssh_string_data(x))) {
Packit Service 31306d
    rc = 0;
Packit Service 31306d
  }
Packit Service 31306d
Packit Service 31306d
error:
Packit Service 31306d
  ssh_string_burn(p);
Packit Service 31306d
  SSH_STRING_FREE(p);
Packit Service 31306d
  ssh_string_burn(q);
Packit Service 31306d
  SSH_STRING_FREE(q);
Packit Service 31306d
  ssh_string_burn(g);
Packit Service 31306d
  SSH_STRING_FREE(g);
Packit Service 31306d
  ssh_string_burn(y);
Packit Service 31306d
  SSH_STRING_FREE(y);
Packit Service 31306d
  ssh_string_burn(x);
Packit Service 31306d
  SSH_STRING_FREE(x);
Packit Service 31306d
  SSH_STRING_FREE(v);
Packit Service 31306d
Packit Service 31306d
  return rc;
Packit Service 31306d
}
Packit Service 31306d
Packit Service 31306d
#ifdef HAVE_GCRYPT_ECC
Packit Service 31306d
static int pki_key_ecdsa_to_nid(gcry_sexp_t k)
Packit Service 31306d
{
Packit Service 31306d
    gcry_sexp_t sexp;
Packit Service 31306d
    const char *tmp;
Packit Service 31306d
    size_t size;
Packit Service 31306d
Packit Service 31306d
    sexp = gcry_sexp_find_token(k, "curve", 0);
Packit Service 31306d
    if (sexp == NULL) {
Packit Service 31306d
        return -1;
Packit Service 31306d
    }
Packit Service 31306d
Packit Service 31306d
    tmp = gcry_sexp_nth_data(sexp, 1, &size);
Packit Service 31306d
Packit Service 31306d
    if (size == 10) {
Packit Service 31306d
        int cmp;
Packit Service 31306d
Packit Service 31306d
        cmp = memcmp("NIST P-256", tmp, size);
Packit Service 31306d
        if (cmp == 0) {
Packit Service 31306d
            gcry_sexp_release(sexp);
Packit Service 31306d
            return NID_gcrypt_nistp256;
Packit Service 31306d
        }
Packit Service 31306d
Packit Service 31306d
        cmp = memcmp("NIST P-384", tmp, size);
Packit Service 31306d
        if (cmp == 0) {
Packit Service 31306d
            gcry_sexp_release(sexp);
Packit Service 31306d
            return NID_gcrypt_nistp384;
Packit Service 31306d
        }
Packit Service 31306d
Packit Service 31306d
        cmp = memcmp("NIST P-521", tmp, size);
Packit Service 31306d
        if (cmp == 0) {
Packit Service 31306d
            gcry_sexp_release(sexp);
Packit Service 31306d
            return NID_gcrypt_nistp521;
Packit Service 31306d
        }
Packit Service 31306d
    }
Packit Service 31306d
Packit Service 31306d
    gcry_sexp_release(sexp);
Packit Service 31306d
    return -1;
Packit Service 31306d
}
Packit Service 31306d
Packit Service 31306d
static enum ssh_keytypes_e pki_key_ecdsa_to_key_type(gcry_sexp_t k)
Packit Service 31306d
{
Packit Service 31306d
    int nid;
Packit Service 31306d
Packit Service 31306d
    nid = pki_key_ecdsa_to_nid(k);
Packit Service 31306d
Packit Service 31306d
    switch (nid) {
Packit Service 31306d
        case NID_gcrypt_nistp256:
Packit Service 31306d
            return SSH_KEYTYPE_ECDSA_P256;
Packit Service 31306d
        case NID_gcrypt_nistp384:
Packit Service 31306d
            return SSH_KEYTYPE_ECDSA_P384;
Packit Service 31306d
        case NID_gcrypt_nistp521:
Packit Service 31306d
            return SSH_KEYTYPE_ECDSA_P521;
Packit Service 31306d
        default:
Packit Service 31306d
            return SSH_KEYTYPE_UNKNOWN;
Packit Service 31306d
    }
Packit Service 31306d
}
Packit Service 31306d
Packit Service 31306d
static const char *pki_key_ecdsa_nid_to_gcrypt_name(int nid)
Packit Service 31306d
{
Packit Service 31306d
    switch (nid) {
Packit Service 31306d
    case NID_gcrypt_nistp256:
Packit Service 31306d
        return "NIST P-256";
Packit Service 31306d
    case NID_gcrypt_nistp384:
Packit Service 31306d
        return "NIST P-384";
Packit Service 31306d
    case NID_gcrypt_nistp521:
Packit Service 31306d
        return "NIST P-521";
Packit Service 31306d
    }
Packit Service 31306d
Packit Service 31306d
    return "unknown";
Packit Service 31306d
}
Packit Service 31306d
Packit Service 31306d
Packit Service 31306d
const char *pki_key_ecdsa_nid_to_name(int nid)
Packit Service 31306d
{
Packit Service 31306d
    switch (nid) {
Packit Service 31306d
    case NID_gcrypt_nistp256:
Packit Service 31306d
        return "ecdsa-sha2-nistp256";
Packit Service 31306d
    case NID_gcrypt_nistp384:
Packit Service 31306d
        return "ecdsa-sha2-nistp384";
Packit Service 31306d
    case NID_gcrypt_nistp521:
Packit Service 31306d
        return "ecdsa-sha2-nistp521";
Packit Service 31306d
    }
Packit Service 31306d
Packit Service 31306d
    return "unknown";
Packit Service 31306d
}
Packit Service 31306d
Packit Service 31306d
static const char *pki_key_ecdsa_nid_to_char(int nid)
Packit Service 31306d
{
Packit Service 31306d
    switch (nid) {
Packit Service 31306d
    case NID_gcrypt_nistp256:
Packit Service 31306d
        return "nistp256";
Packit Service 31306d
    case NID_gcrypt_nistp384:
Packit Service 31306d
        return "nistp384";
Packit Service 31306d
    case NID_gcrypt_nistp521:
Packit Service 31306d
        return "nistp521";
Packit Service 31306d
    default:
Packit Service 31306d
        break;
Packit Service 31306d
    }
Packit Service 31306d
Packit Service 31306d
    return "unknown";
Packit Service 31306d
}
Packit Service 31306d
Packit Service 31306d
int pki_key_ecdsa_nid_from_name(const char *name)
Packit Service 31306d
{
Packit Service 31306d
    int cmp;
Packit Service 31306d
Packit Service 31306d
    cmp = strcmp(name, "nistp256");
Packit Service 31306d
    if (cmp == 0) {
Packit Service 31306d
        return NID_gcrypt_nistp256;
Packit Service 31306d
    }
Packit Service 31306d
Packit Service 31306d
    cmp = strcmp(name, "nistp384");
Packit Service 31306d
    if (cmp == 0) {
Packit Service 31306d
        return NID_gcrypt_nistp384;
Packit Service 31306d
    }
Packit Service 31306d
Packit Service 31306d
    cmp = strcmp(name, "nistp521");
Packit Service 31306d
    if (cmp == 0) {
Packit Service 31306d
        return NID_gcrypt_nistp521;
Packit Service 31306d
    }
Packit Service 31306d
Packit Service 31306d
    return -1;
Packit Service 31306d
}
Packit Service 31306d
Packit Service 31306d
static int asn1_oi_to_nid(const ssh_string oi)
Packit Service 31306d
{
Packit Service 31306d
    static const struct {
Packit Service 31306d
        int nid;
Packit Service 31306d
        size_t length;
Packit Service 31306d
        const char *identifier;
Packit Service 31306d
    } *e, mapping[] = {
Packit Service 31306d
        {NID_gcrypt_nistp256, 8, "\x2a\x86\x48\xce\x3d\x03\x01\x07"},
Packit Service 31306d
        {NID_gcrypt_nistp384, 5, "\x2b\x81\x04\x00\x22"},
Packit Service 31306d
        {NID_gcrypt_nistp521, 5, "\x2b\x81\x04\x00\x23"},
Packit Service 31306d
        {0},
Packit Service 31306d
    };
Packit Service 31306d
    size_t len = ssh_string_len(oi);
Packit Service 31306d
    for (e = mapping; e->length; e++) {
Packit Service 31306d
        if (len == e->length
Packit Service 31306d
            && memcmp(ssh_string_data(oi), e->identifier, len) == 0) {
Packit Service 31306d
            return e->nid;
Packit Service 31306d
        }
Packit Service 31306d
    }
Packit Service 31306d
    return -1;
Packit Service 31306d
}
Packit Service 31306d
Packit Service 31306d
static int b64decode_ecdsa_privatekey(const char *pkey, gcry_sexp_t *r,
Packit Service 31306d
                                      ssh_auth_callback cb,
Packit Service 31306d
                                      void *userdata,
Packit Service 31306d
                                      const char *desc)
Packit Service 31306d
{
Packit Service 31306d
    const unsigned char *data;
Packit Service 31306d
    ssh_buffer buffer = NULL;
Packit Service 31306d
    gcry_error_t err = 0;
Packit Service 31306d
    ssh_string v = NULL;
Packit Service 31306d
    ssh_string d = NULL;
Packit Service 31306d
    ssh_string oi = NULL;
Packit Service 31306d
    int nid;
Packit Service 31306d
    ssh_string q = NULL;
Packit Service 31306d
    int valid = 0;
Packit Service 31306d
    int ok;
Packit Service 31306d
Packit Service 31306d
    buffer = privatekey_string_to_buffer(pkey,
Packit Service 31306d
                                         SSH_KEYTYPE_ECDSA_P256,
Packit Service 31306d
                                         cb,
Packit Service 31306d
                                         userdata,
Packit Service 31306d
                                         desc);
Packit Service 31306d
    if (buffer == NULL) {
Packit Service 31306d
        goto error;
Packit Service 31306d
    }
Packit Service 31306d
Packit Service 31306d
    ok = asn1_check_sequence(buffer);
Packit Service 31306d
    if (!ok) {
Packit Service 31306d
        goto error;
Packit Service 31306d
    }
Packit Service 31306d
Packit Service 31306d
    /* RFC5915 specifies version 1.  */
Packit Service 31306d
    v = asn1_get_int(buffer);
Packit Service 31306d
    if (v == NULL) {
Packit Service 31306d
        goto error;
Packit Service 31306d
    }
Packit Service 31306d
Packit Service 31306d
    data = ssh_string_data(v);
Packit Service 31306d
    if (ssh_string_len(v) != 1 || data[0] != 1) {
Packit Service 31306d
        goto error;
Packit Service 31306d
    }
Packit Service 31306d
Packit Service 31306d
    d = asn1_get(buffer, ASN1_OCTET_STRING);
Packit Service 31306d
    if (!asn1_check_tag(buffer, 0xa0)) {
Packit Service 31306d
        goto error;
Packit Service 31306d
    }
Packit Service 31306d
    oi = asn1_get(buffer, ASN1_OBJECT_IDENTIFIER);
Packit Service 31306d
    nid = asn1_oi_to_nid(oi);
Packit Service 31306d
    ok = asn1_check_tag(buffer, 0xa1);
Packit Service 31306d
    if (!ok) {
Packit Service 31306d
        goto error;
Packit Service 31306d
    }
Packit Service 31306d
    q = asn1_get_bit_string(buffer);
Packit Service 31306d
Packit Service 31306d
    if (d == NULL || oi == NULL || nid == -1 || q == NULL) {
Packit Service 31306d
        goto error;
Packit Service 31306d
    }
Packit Service 31306d
Packit Service 31306d
    err = gcry_sexp_build(r,
Packit Service 31306d
                          NULL,
Packit Service 31306d
                          "(private-key(ecdsa(curve %s)(d %b)(q %b)))",
Packit Service 31306d
                          pki_key_ecdsa_nid_to_gcrypt_name(nid),
Packit Service 31306d
                          ssh_string_len(d),
Packit Service 31306d
                          ssh_string_data(d),
Packit Service 31306d
                          ssh_string_len(q),
Packit Service 31306d
                          ssh_string_data(q));
Packit Service 31306d
    if (err == 0) {
Packit Service 31306d
        valid = 1;
Packit Service 31306d
    }
Packit Service 31306d
Packit Service 31306d
 error:
Packit Service 31306d
    SSH_BUFFER_FREE(buffer);
Packit Service 31306d
    SSH_STRING_FREE(v);
Packit Service 31306d
    ssh_string_burn(d);
Packit Service 31306d
    SSH_STRING_FREE(d);
Packit Service 31306d
    SSH_STRING_FREE(oi);
Packit Service 31306d
    ssh_string_burn(q);
Packit Service 31306d
    SSH_STRING_FREE(q);
Packit Service 31306d
Packit Service 31306d
    return valid;
Packit Service 31306d
}
Packit Service 31306d
#endif
Packit Service 31306d
Packit Service 31306d
ssh_string pki_private_key_to_pem(const ssh_key key,
Packit Service 31306d
                                  const char *passphrase,
Packit Service 31306d
                                  ssh_auth_callback auth_fn,
Packit Service 31306d
                                  void *auth_data)
Packit Service 31306d
{
Packit Service 31306d
    (void) key;
Packit Service 31306d
    (void) passphrase;
Packit Service 31306d
    (void) auth_fn;
Packit Service 31306d
    (void) auth_data;
Packit Service 31306d
Packit Service 31306d
    SSH_LOG(SSH_LOG_WARN, "PEM export not supported by gcrypt backend!");
Packit Service 31306d
Packit Service 31306d
    return NULL;
Packit Service 31306d
}
Packit Service 31306d
Packit Service 31306d
ssh_key pki_private_key_from_base64(const char *b64_key,
Packit Service 31306d
                                    const char *passphrase,
Packit Service 31306d
                                    ssh_auth_callback auth_fn,
Packit Service 31306d
                                    void *auth_data)
Packit Service 31306d
{
Packit Service 31306d
    gcry_sexp_t dsa = NULL;
Packit Service 31306d
    gcry_sexp_t rsa = NULL;
Packit Service 31306d
    gcry_sexp_t ecdsa = NULL;
Packit Service 31306d
    ssh_key key = NULL;
Packit Service 31306d
    enum ssh_keytypes_e type;
Packit Service 31306d
    int valid;
Packit Service 31306d
Packit Service 31306d
    type = pki_privatekey_type_from_string(b64_key);
Packit Service 31306d
    if (type == SSH_KEYTYPE_UNKNOWN) {
Packit Service 31306d
        SSH_LOG(SSH_LOG_WARN, "Unknown or invalid private key.");
Packit Service 31306d
        return NULL;
Packit Service 31306d
    }
Packit Service 31306d
Packit Service 31306d
    switch (type) {
Packit Service 31306d
        case SSH_KEYTYPE_DSS:
Packit Service 31306d
            if (passphrase == NULL) {
Packit Service 31306d
                if (auth_fn) {
Packit Service 31306d
                    valid = b64decode_dsa_privatekey(b64_key, &dsa, auth_fn,
Packit Service 31306d
                            auth_data, "Passphrase for private key:");
Packit Service 31306d
                } else {
Packit Service 31306d
                    valid = b64decode_dsa_privatekey(b64_key, &dsa, NULL, NULL,
Packit Service 31306d
                            NULL);
Packit Service 31306d
                }
Packit Service 31306d
            } else {
Packit Service 31306d
                valid = b64decode_dsa_privatekey(b64_key, &dsa, NULL, (void *)
Packit Service 31306d
                        passphrase, NULL);
Packit Service 31306d
            }
Packit Service 31306d
Packit Service 31306d
            if (!valid) {
Packit Service 31306d
                SSH_LOG(SSH_LOG_WARN, "Parsing private key");
Packit Service 31306d
                goto fail;
Packit Service 31306d
            }
Packit Service 31306d
            break;
Packit Service 31306d
        case SSH_KEYTYPE_RSA:
Packit Service 31306d
            if (passphrase == NULL) {
Packit Service 31306d
                if (auth_fn) {
Packit Service 31306d
                    valid = b64decode_rsa_privatekey(b64_key, &rsa, auth_fn,
Packit Service 31306d
                            auth_data, "Passphrase for private key:");
Packit Service 31306d
                } else {
Packit Service 31306d
                    valid = b64decode_rsa_privatekey(b64_key, &rsa, NULL, NULL,
Packit Service 31306d
                            NULL);
Packit Service 31306d
                }
Packit Service 31306d
            } else {
Packit Service 31306d
                valid = b64decode_rsa_privatekey(b64_key, &rsa, NULL,
Packit Service 31306d
                        (void *)passphrase, NULL);
Packit Service 31306d
            }
Packit Service 31306d
Packit Service 31306d
            if (!valid) {
Packit Service 31306d
                SSH_LOG(SSH_LOG_WARN, "Parsing private key");
Packit Service 31306d
                goto fail;
Packit Service 31306d
            }
Packit Service 31306d
            break;
Packit Service 31306d
        case SSH_KEYTYPE_ECDSA_P256:
Packit Service 31306d
        case SSH_KEYTYPE_ECDSA_P384:
Packit Service 31306d
        case SSH_KEYTYPE_ECDSA_P521:
Packit Service 31306d
#if HAVE_GCRYPT_ECC
Packit Service 31306d
            if (passphrase == NULL) {
Packit Service 31306d
                if (auth_fn != NULL) {
Packit Service 31306d
                    valid = b64decode_ecdsa_privatekey(b64_key,
Packit Service 31306d
                                                       &ecdsa,
Packit Service 31306d
                                                       auth_fn,
Packit Service 31306d
                                                       auth_data,
Packit Service 31306d
                                                       "Passphrase for private key:");
Packit Service 31306d
                } else {
Packit Service 31306d
                    valid = b64decode_ecdsa_privatekey(b64_key,
Packit Service 31306d
                                                       &ecdsa,
Packit Service 31306d
                                                       NULL,
Packit Service 31306d
                                                       NULL,
Packit Service 31306d
                                                       NULL);
Packit Service 31306d
                }
Packit Service 31306d
            } else {
Packit Service 31306d
                valid = b64decode_ecdsa_privatekey(b64_key,
Packit Service 31306d
                                                   &ecdsa,
Packit Service 31306d
                                                   NULL,
Packit Service 31306d
                                                   (void *)passphrase,
Packit Service 31306d
                                                   NULL);
Packit Service 31306d
            }
Packit Service 31306d
Packit Service 31306d
            if (!valid) {
Packit Service 31306d
                SSH_LOG(SSH_LOG_WARN, "Parsing private key");
Packit Service 31306d
                goto fail;
Packit Service 31306d
            }
Packit Service 31306d
Packit Service 31306d
            /* pki_privatekey_type_from_string always returns P256 for ECDSA
Packit Service 31306d
             * keys, so we need to figure out the correct type here */
Packit Service 31306d
            type = pki_key_ecdsa_to_key_type(ecdsa);
Packit Service 31306d
            if (type == SSH_KEYTYPE_UNKNOWN) {
Packit Service 31306d
                SSH_LOG(SSH_LOG_WARN, "Invalid private key.");
Packit Service 31306d
                goto fail;
Packit Service 31306d
            }
Packit Service 31306d
            break;
Packit Service 31306d
#endif
Packit Service 31306d
        case SSH_KEYTYPE_ED25519:
Packit Service 31306d
            /* Cannot open ed25519 keys with libgcrypt */
Packit Service 31306d
        case SSH_KEYTYPE_RSA1:
Packit Service 31306d
        case SSH_KEYTYPE_UNKNOWN:
Packit Service 31306d
        default:
Packit Service 31306d
            SSH_LOG(SSH_LOG_WARN, "Unknown or invalid private key type %d", type);
Packit Service 31306d
            return NULL;
Packit Service 31306d
    }
Packit Service 31306d
Packit Service 31306d
    key = ssh_key_new();
Packit Service 31306d
    if (key == NULL) {
Packit Service 31306d
        goto fail;
Packit Service 31306d
    }
Packit Service 31306d
Packit Service 31306d
    key->type = type;
Packit Service 31306d
    key->type_c = ssh_key_type_to_char(type);
Packit Service 31306d
    key->flags = SSH_KEY_FLAG_PRIVATE | SSH_KEY_FLAG_PUBLIC;
Packit Service 31306d
    key->dsa = dsa;
Packit Service 31306d
    key->rsa = rsa;
Packit Service 31306d
    key->ecdsa = ecdsa;
Packit Service 31306d
#ifdef HAVE_GCRYPT_ECC
Packit Service 31306d
    if (is_ecdsa_key_type(key->type)) {
Packit Service 31306d
        key->ecdsa_nid = pki_key_ecdsa_to_nid(key->ecdsa);
Packit Service 31306d
    }
Packit Service 31306d
#endif
Packit Service 31306d
Packit Service 31306d
    return key;
Packit Service 31306d
fail:
Packit Service 31306d
    ssh_key_free(key);
Packit Service 31306d
    gcry_sexp_release(dsa);
Packit Service 31306d
    gcry_sexp_release(rsa);
Packit Service 31306d
    gcry_sexp_release(ecdsa);
Packit Service 31306d
Packit Service 31306d
    return NULL;
Packit Service 31306d
}
Packit Service 31306d
Packit Service 31306d
int pki_privkey_build_dss(ssh_key key,
Packit Service 31306d
                          ssh_string p,
Packit Service 31306d
                          ssh_string q,
Packit Service 31306d
                          ssh_string g,
Packit Service 31306d
                          ssh_string pubkey,
Packit Service 31306d
                          ssh_string privkey)
Packit Service 31306d
{
Packit Service 31306d
    gcry_sexp_build(&key->dsa, NULL,
Packit Service 31306d
            "(private-key(dsa(p %b)(q %b)(g %b)(y %b)(x %b)))",
Packit Service 31306d
            ssh_string_len(p), ssh_string_data(p),
Packit Service 31306d
            ssh_string_len(q), ssh_string_data(q),
Packit Service 31306d
            ssh_string_len(g), ssh_string_data(g),
Packit Service 31306d
            ssh_string_len(pubkey), ssh_string_data(pubkey),
Packit Service 31306d
            ssh_string_len(privkey), ssh_string_data(privkey));
Packit Service 31306d
    if (key->dsa == NULL) {
Packit Service 31306d
        return SSH_ERROR;
Packit Service 31306d
    }
Packit Service 31306d
Packit Service 31306d
    return SSH_OK;
Packit Service 31306d
}
Packit Service 31306d
Packit Service 31306d
int pki_pubkey_build_dss(ssh_key key,
Packit Service 31306d
                         ssh_string p,
Packit Service 31306d
                         ssh_string q,
Packit Service 31306d
                         ssh_string g,
Packit Service 31306d
                         ssh_string pubkey) {
Packit Service 31306d
    gcry_sexp_build(&key->dsa, NULL,
Packit Service 31306d
            "(public-key(dsa(p %b)(q %b)(g %b)(y %b)))",
Packit Service 31306d
            ssh_string_len(p), ssh_string_data(p),
Packit Service 31306d
            ssh_string_len(q), ssh_string_data(q),
Packit Service 31306d
            ssh_string_len(g), ssh_string_data(g),
Packit Service 31306d
            ssh_string_len(pubkey), ssh_string_data(pubkey));
Packit Service 31306d
    if (key->dsa == NULL) {
Packit Service 31306d
        return SSH_ERROR;
Packit Service 31306d
    }
Packit Service 31306d
Packit Service 31306d
    return SSH_OK;
Packit Service 31306d
}
Packit Service 31306d
Packit Service 31306d
int pki_privkey_build_rsa(ssh_key key,
Packit Service 31306d
                          ssh_string n,
Packit Service 31306d
                          ssh_string e,
Packit Service 31306d
                          ssh_string d,
Packit Service 31306d
                          ssh_string iqmp,
Packit Service 31306d
                          ssh_string p,
Packit Service 31306d
                          ssh_string q)
Packit Service 31306d
{
Packit Service 31306d
    /* in gcrypt, there is no iqmp (inverse of q mod p) argument,
Packit Service 31306d
     * but it is ipmq (inverse of p mod q) so we need to swap
Packit Service 31306d
     * the p and q arguments */
Packit Service 31306d
    gcry_sexp_build(&key->rsa, NULL,
Packit Service 31306d
            "(private-key(rsa(n %b)(e %b)(d %b)(p %b)(q %b)(u %b)))",
Packit Service 31306d
            ssh_string_len(n), ssh_string_data(n),
Packit Service 31306d
            ssh_string_len(e), ssh_string_data(e),
Packit Service 31306d
            ssh_string_len(d), ssh_string_data(d),
Packit Service 31306d
            ssh_string_len(q), ssh_string_data(q),
Packit Service 31306d
            ssh_string_len(p), ssh_string_data(p),
Packit Service 31306d
            ssh_string_len(iqmp), ssh_string_data(iqmp));
Packit Service 31306d
    if (key->rsa == NULL) {
Packit Service 31306d
        return SSH_ERROR;
Packit Service 31306d
    }
Packit Service 31306d
Packit Service 31306d
    return SSH_OK;
Packit Service 31306d
}
Packit Service 31306d
Packit Service 31306d
int pki_pubkey_build_rsa(ssh_key key,
Packit Service 31306d
                         ssh_string e,
Packit Service 31306d
                         ssh_string n) {
Packit Service 31306d
    gcry_sexp_build(&key->rsa, NULL,
Packit Service 31306d
            "(public-key(rsa(n %b)(e %b)))",
Packit Service 31306d
            ssh_string_len(n), ssh_string_data(n),
Packit Service 31306d
            ssh_string_len(e),ssh_string_data(e));
Packit Service 31306d
    if (key->rsa == NULL) {
Packit Service 31306d
        return SSH_ERROR;
Packit Service 31306d
    }
Packit Service 31306d
Packit Service 31306d
    return SSH_OK;
Packit Service 31306d
}
Packit Service 31306d
Packit Service 31306d
#ifdef HAVE_GCRYPT_ECC
Packit Service 31306d
int pki_privkey_build_ecdsa(ssh_key key, int nid, ssh_string e, ssh_string exp)
Packit Service 31306d
{
Packit Service 31306d
    gpg_error_t err;
Packit Service 31306d
Packit Service 31306d
    key->ecdsa_nid = nid;
Packit Service 31306d
    key->type_c = pki_key_ecdsa_nid_to_name(nid);
Packit Service 31306d
Packit Service 31306d
    err = gcry_sexp_build(&key->ecdsa, NULL,
Packit Service 31306d
                          "(private-key(ecdsa(curve %s)(d %b)(q %b)))",
Packit Service 31306d
                          pki_key_ecdsa_nid_to_gcrypt_name(nid),
Packit Service 31306d
                          ssh_string_len(exp), ssh_string_data(exp),
Packit Service 31306d
                          ssh_string_len(e), ssh_string_data(e));
Packit Service 31306d
    if (err) {
Packit Service 31306d
        return SSH_ERROR;
Packit Service 31306d
    }
Packit Service 31306d
Packit Service 31306d
    return SSH_OK;
Packit Service 31306d
}
Packit Service 31306d
Packit Service 31306d
int pki_pubkey_build_ecdsa(ssh_key key, int nid, ssh_string e)
Packit Service 31306d
{
Packit Service 31306d
    gpg_error_t err;
Packit Service 31306d
Packit Service 31306d
    key->ecdsa_nid = nid;
Packit Service 31306d
    key->type_c = pki_key_ecdsa_nid_to_name(nid);
Packit Service 31306d
Packit Service 31306d
    err = gcry_sexp_build(&key->ecdsa, NULL,
Packit Service 31306d
                          "(public-key(ecdsa(curve %s)(q %b)))",
Packit Service 31306d
                          pki_key_ecdsa_nid_to_gcrypt_name(nid),
Packit Service 31306d
                          ssh_string_len(e), ssh_string_data(e));
Packit Service 31306d
    if (err) {
Packit Service 31306d
        return SSH_ERROR;
Packit Service 31306d
    }
Packit Service 31306d
Packit Service 31306d
    return SSH_OK;
Packit Service 31306d
}
Packit Service 31306d
#endif
Packit Service 31306d
Packit Service 31306d
ssh_key pki_key_dup(const ssh_key key, int demote)
Packit Service 31306d
{
Packit Service 31306d
    ssh_key new;
Packit Service 31306d
    gcry_error_t err = 0;
Packit Service 31306d
    int rc;
Packit Service 31306d
Packit Service 31306d
    gcry_mpi_t p = NULL;
Packit Service 31306d
    gcry_mpi_t q = NULL;
Packit Service 31306d
    gcry_mpi_t g = NULL;
Packit Service 31306d
    gcry_mpi_t y = NULL;
Packit Service 31306d
    gcry_mpi_t x = NULL;
Packit Service 31306d
Packit Service 31306d
    gcry_mpi_t e = NULL;
Packit Service 31306d
    gcry_mpi_t n = NULL;
Packit Service 31306d
    gcry_mpi_t d = NULL;
Packit Service 31306d
    gcry_mpi_t u = NULL;
Packit Service 31306d
Packit Service 31306d
    gcry_sexp_t curve = NULL;
Packit Service 31306d
Packit Service 31306d
    new = ssh_key_new();
Packit Service 31306d
    if (new == NULL) {
Packit Service 31306d
        return NULL;
Packit Service 31306d
    }
Packit Service 31306d
    new->type = key->type;
Packit Service 31306d
    new->type_c = key->type_c;
Packit Service 31306d
    if (demote) {
Packit Service 31306d
        new->flags = SSH_KEY_FLAG_PUBLIC;
Packit Service 31306d
    } else {
Packit Service 31306d
        new->flags = key->flags;
Packit Service 31306d
    }
Packit Service 31306d
Packit Service 31306d
    switch(key->type) {
Packit Service 31306d
        case SSH_KEYTYPE_DSS:
Packit Service 31306d
            err = gcry_sexp_extract_param(key->dsa,
Packit Service 31306d
                                          NULL,
Packit Service 31306d
                                          "pqgyx?",
Packit Service 31306d
                                          &p,
Packit Service 31306d
                                          &q,
Packit Service 31306d
                                          &g,
Packit Service 31306d
                                          &y,
Packit Service 31306d
                                          &x,
Packit Service 31306d
                                          NULL);
Packit Service 31306d
            if (err != 0) {
Packit Service 31306d
                break;
Packit Service 31306d
            }
Packit Service 31306d
Packit Service 31306d
            if (!demote && (key->flags & SSH_KEY_FLAG_PRIVATE)) {
Packit Service 31306d
                err = gcry_sexp_build(&new->dsa,
Packit Service 31306d
                        NULL,
Packit Service 31306d
                        "(private-key(dsa(p %m)(q %m)(g %m)(y %m)(x %m)))",
Packit Service 31306d
                        p, q, g, y, x);
Packit Service 31306d
            } else {
Packit Service 31306d
                err = gcry_sexp_build(&new->dsa,
Packit Service 31306d
                        NULL,
Packit Service 31306d
                        "(public-key(dsa(p %m)(q %m)(g %m)(y %m)))",
Packit Service 31306d
                        p, q, g, y);
Packit Service 31306d
            }
Packit Service 31306d
            break;
Packit Service 31306d
        case SSH_KEYTYPE_RSA:
Packit Service 31306d
            err = gcry_sexp_extract_param(key->rsa,
Packit Service 31306d
                                          NULL,
Packit Service 31306d
                                          "ned?p?q?u?",
Packit Service 31306d
                                          &n,
Packit Service 31306d
                                          &e,
Packit Service 31306d
                                          &d,
Packit Service 31306d
                                          &p,
Packit Service 31306d
                                          &q,
Packit Service 31306d
                                          &u,
Packit Service 31306d
                                          NULL);
Packit Service 31306d
            if (err != 0) {
Packit Service 31306d
                break;
Packit Service 31306d
            }
Packit Service 31306d
Packit Service 31306d
            if (!demote && (key->flags & SSH_KEY_FLAG_PRIVATE)) {
Packit Service 31306d
                err = gcry_sexp_build(&new->rsa,
Packit Service 31306d
                        NULL,
Packit Service 31306d
                        "(private-key(rsa(n %m)(e %m)(d %m)(p %m)(q %m)(u %m)))",
Packit Service 31306d
                        n, e, d, p, q, u);
Packit Service 31306d
            } else {
Packit Service 31306d
                err = gcry_sexp_build(&new->rsa,
Packit Service 31306d
                                      NULL,
Packit Service 31306d
                                      "(public-key(rsa(n %m)(e %m)))",
Packit Service 31306d
                                      n, e);
Packit Service 31306d
            }
Packit Service 31306d
            break;
Packit Service 31306d
        case SSH_KEYTYPE_ED25519:
Packit Service 31306d
		rc = pki_ed25519_key_dup(new, key);
Packit Service 31306d
		if (rc != SSH_OK) {
Packit Service 31306d
                    ssh_key_free(new);
Packit Service 31306d
                    return NULL;
Packit Service 31306d
		}
Packit Service 31306d
		break;
Packit Service 31306d
Packit Service 31306d
        case SSH_KEYTYPE_ECDSA_P256:
Packit Service 31306d
        case SSH_KEYTYPE_ECDSA_P384:
Packit Service 31306d
        case SSH_KEYTYPE_ECDSA_P521:
Packit Service 31306d
#ifdef HAVE_GCRYPT_ECC
Packit Service 31306d
            new->ecdsa_nid = key->ecdsa_nid;
Packit Service 31306d
Packit Service 31306d
            err = gcry_sexp_extract_param(key->ecdsa,
Packit Service 31306d
                                          NULL,
Packit Service 31306d
                                          "qd?",
Packit Service 31306d
                                          &q,
Packit Service 31306d
                                          &d,
Packit Service 31306d
                                          NULL);
Packit Service 31306d
            if (err) {
Packit Service 31306d
                break;
Packit Service 31306d
            }
Packit Service 31306d
Packit Service 31306d
            curve = gcry_sexp_find_token(key->ecdsa, "curve", 0);
Packit Service 31306d
            if (curve == NULL) {
Packit Service 31306d
              break;
Packit Service 31306d
            }
Packit Service 31306d
Packit Service 31306d
            if (!demote && (key->flags & SSH_KEY_FLAG_PRIVATE)) {
Packit Service 31306d
                err = gcry_sexp_build(&new->ecdsa,
Packit Service 31306d
                                      NULL,
Packit Service 31306d
                                      "(private-key(ecdsa %S (d %m)(q %m)))",
Packit Service 31306d
                                      curve,
Packit Service 31306d
                                      d,
Packit Service 31306d
                                      q);
Packit Service 31306d
            } else {
Packit Service 31306d
                err = gcry_sexp_build(&new->ecdsa,
Packit Service 31306d
                                      NULL,
Packit Service 31306d
                                      "(private-key(ecdsa %S (q %m)))",
Packit Service 31306d
                                      curve,
Packit Service 31306d
                                      q);
Packit Service 31306d
            }
Packit Service 31306d
            break;
Packit Service 31306d
#endif
Packit Service 31306d
        case SSH_KEYTYPE_RSA1:
Packit Service 31306d
        case SSH_KEYTYPE_UNKNOWN:
Packit Service 31306d
        default:
Packit Service 31306d
            ssh_key_free(new);
Packit Service 31306d
            return NULL;
Packit Service 31306d
    }
Packit Service 31306d
Packit Service 31306d
    if (err) {
Packit Service 31306d
        ssh_key_free(new);
Packit Service 31306d
        new = NULL;
Packit Service 31306d
    }
Packit Service 31306d
Packit Service 31306d
    gcry_mpi_release(p);
Packit Service 31306d
    gcry_mpi_release(q);
Packit Service 31306d
    gcry_mpi_release(g);
Packit Service 31306d
    gcry_mpi_release(y);
Packit Service 31306d
    gcry_mpi_release(x);
Packit Service 31306d
Packit Service 31306d
    gcry_mpi_release(e);
Packit Service 31306d
    gcry_mpi_release(n);
Packit Service 31306d
    gcry_mpi_release(d);
Packit Service 31306d
    gcry_mpi_release(u);
Packit Service 31306d
Packit Service 31306d
    gcry_sexp_release(curve);
Packit Service 31306d
Packit Service 31306d
    return new;
Packit Service 31306d
}
Packit Service 31306d
Packit Service 31306d
static int pki_key_generate(ssh_key key, int parameter, const char *type_s, int type){
Packit Service 31306d
    gcry_sexp_t parms;
Packit Service 31306d
    int rc;
Packit Service 31306d
    rc = gcry_sexp_build(&parms,
Packit Service 31306d
            NULL,
Packit Service 31306d
            "(genkey(%s(nbits %d)(transient-key)))",
Packit Service 31306d
            type_s,
Packit Service 31306d
            parameter);
Packit Service 31306d
    if (rc != 0)
Packit Service 31306d
        return SSH_ERROR;
Packit Service 31306d
    switch (type) {
Packit Service 31306d
    case SSH_KEYTYPE_RSA:
Packit Service 31306d
        rc = gcry_pk_genkey(&key->rsa, parms);
Packit Service 31306d
        break;
Packit Service 31306d
    case SSH_KEYTYPE_DSS:
Packit Service 31306d
        rc = gcry_pk_genkey(&key->dsa, parms);
Packit Service 31306d
        break;
Packit Service 31306d
    case SSH_KEYTYPE_ECDSA_P256:
Packit Service 31306d
    case SSH_KEYTYPE_ECDSA_P384:
Packit Service 31306d
    case SSH_KEYTYPE_ECDSA_P521:
Packit Service 31306d
        rc = gcry_pk_genkey(&key->ecdsa, parms);
Packit Service 31306d
        break;
Packit Service 31306d
    default:
Packit Service 31306d
        assert (! "reached");
Packit Service 31306d
    }
Packit Service 31306d
    gcry_sexp_release(parms);
Packit Service 31306d
    if (rc != 0)
Packit Service 31306d
        return SSH_ERROR;
Packit Service 31306d
    return SSH_OK;
Packit Service 31306d
}
Packit Service 31306d
Packit Service 31306d
int pki_key_generate_rsa(ssh_key key, int parameter){
Packit Service 31306d
    return pki_key_generate(key, parameter, "rsa", SSH_KEYTYPE_RSA);
Packit Service 31306d
}
Packit Service 31306d
int pki_key_generate_dss(ssh_key key, int parameter){
Packit Service 31306d
    return pki_key_generate(key, parameter, "dsa", SSH_KEYTYPE_DSS);
Packit Service 31306d
}
Packit Service 31306d
Packit Service 31306d
#ifdef HAVE_GCRYPT_ECC
Packit Service 31306d
int pki_key_generate_ecdsa(ssh_key key, int parameter) {
Packit Service 31306d
    switch (parameter) {
Packit Service 31306d
        case 384:
Packit Service 31306d
            key->ecdsa_nid = NID_gcrypt_nistp384;
Packit Service 31306d
            key->type = SSH_KEYTYPE_ECDSA_P384;
Packit Service 31306d
            return pki_key_generate(key, parameter, "ecdsa",
Packit Service 31306d
                                    SSH_KEYTYPE_ECDSA_P384);
Packit Service 31306d
        case 521:
Packit Service 31306d
            key->ecdsa_nid = NID_gcrypt_nistp521;
Packit Service 31306d
            key->type = SSH_KEYTYPE_ECDSA_P521;
Packit Service 31306d
            return pki_key_generate(key, parameter, "ecdsa",
Packit Service 31306d
                                    SSH_KEYTYPE_ECDSA_P521);
Packit Service 31306d
        case 256:
Packit Service 31306d
        default:
Packit Service 31306d
            key->ecdsa_nid = NID_gcrypt_nistp256;
Packit Service 31306d
            key->type = SSH_KEYTYPE_ECDSA_P256;
Packit Service 31306d
            return pki_key_generate(key, parameter, "ecdsa",
Packit Service 31306d
                                    SSH_KEYTYPE_ECDSA_P256);
Packit Service 31306d
    }
Packit Service 31306d
}
Packit Service 31306d
#endif
Packit Service 31306d
Packit Service 31306d
static int _bignum_cmp(const gcry_sexp_t s1,
Packit Service 31306d
                       const gcry_sexp_t s2,
Packit Service 31306d
                       const char *what)
Packit Service 31306d
{
Packit Service 31306d
    gcry_sexp_t sexp;
Packit Service 31306d
    bignum b1;
Packit Service 31306d
    bignum b2;
Packit Service 31306d
    int result;
Packit Service 31306d
Packit Service 31306d
    sexp = gcry_sexp_find_token(s1, what, 0);
Packit Service 31306d
    if (sexp == NULL) {
Packit Service 31306d
        return 1;
Packit Service 31306d
    }
Packit Service 31306d
    b1 = gcry_sexp_nth_mpi(sexp, 1, GCRYMPI_FMT_USG);
Packit Service 31306d
    gcry_sexp_release(sexp);
Packit Service 31306d
    if (b1 == NULL) {
Packit Service 31306d
        return 1;
Packit Service 31306d
    }
Packit Service 31306d
Packit Service 31306d
    sexp = gcry_sexp_find_token(s2, what, 0);
Packit Service 31306d
    if (sexp == NULL) {
Packit Service 31306d
        bignum_safe_free(b1);
Packit Service 31306d
        return 1;
Packit Service 31306d
    }
Packit Service 31306d
    b2 = gcry_sexp_nth_mpi(sexp, 1, GCRYMPI_FMT_USG);
Packit Service 31306d
    gcry_sexp_release(sexp);
Packit Service 31306d
    if (b2 == NULL) {
Packit Service 31306d
        bignum_safe_free(b1);
Packit Service 31306d
        return 1;
Packit Service 31306d
    }
Packit Service 31306d
Packit Service 31306d
    result = !! bignum_cmp(b1, b2);
Packit Service 31306d
    bignum_safe_free(b1);
Packit Service 31306d
    bignum_safe_free(b2);
Packit Service 31306d
    return result;
Packit Service 31306d
}
Packit Service 31306d
Packit Service 31306d
int pki_key_compare(const ssh_key k1,
Packit Service 31306d
                    const ssh_key k2,
Packit Service 31306d
                    enum ssh_keycmp_e what)
Packit Service 31306d
{
Packit Service 31306d
    switch (k1->type) {
Packit Service 31306d
        case SSH_KEYTYPE_DSS:
Packit Service 31306d
            if (_bignum_cmp(k1->dsa, k2->dsa, "p") != 0) {
Packit Service 31306d
                return 1;
Packit Service 31306d
            }
Packit Service 31306d
Packit Service 31306d
            if (_bignum_cmp(k1->dsa, k2->dsa, "q") != 0) {
Packit Service 31306d
                return 1;
Packit Service 31306d
            }
Packit Service 31306d
Packit Service 31306d
            if (_bignum_cmp(k1->dsa, k2->dsa, "g") != 0) {
Packit Service 31306d
                return 1;
Packit Service 31306d
            }
Packit Service 31306d
Packit Service 31306d
            if (_bignum_cmp(k1->dsa, k2->dsa, "y") != 0) {
Packit Service 31306d
                return 1;
Packit Service 31306d
            }
Packit Service 31306d
Packit Service 31306d
            if (what == SSH_KEY_CMP_PRIVATE) {
Packit Service 31306d
                if (_bignum_cmp(k1->dsa, k2->dsa, "x") != 0) {
Packit Service 31306d
                    return 1;
Packit Service 31306d
                }
Packit Service 31306d
            }
Packit Service 31306d
            break;
Packit Service 31306d
        case SSH_KEYTYPE_RSA:
Packit Service 31306d
            if (_bignum_cmp(k1->rsa, k2->rsa, "e") != 0) {
Packit Service 31306d
                return 1;
Packit Service 31306d
            }
Packit Service 31306d
Packit Service 31306d
            if (_bignum_cmp(k1->rsa, k2->rsa, "n") != 0) {
Packit Service 31306d
                return 1;
Packit Service 31306d
            }
Packit Service 31306d
Packit Service 31306d
            if (what == SSH_KEY_CMP_PRIVATE) {
Packit Service 31306d
                if (_bignum_cmp(k1->rsa, k2->rsa, "d") != 0) {
Packit Service 31306d
                    return 1;
Packit Service 31306d
                }
Packit Service 31306d
Packit Service 31306d
                if (_bignum_cmp(k1->rsa, k2->rsa, "p") != 0) {
Packit Service 31306d
                    return 1;
Packit Service 31306d
                }
Packit Service 31306d
Packit Service 31306d
                if (_bignum_cmp(k1->rsa, k2->rsa, "q") != 0) {
Packit Service 31306d
                    return 1;
Packit Service 31306d
                }
Packit Service 31306d
Packit Service 31306d
                if (_bignum_cmp(k1->rsa, k2->rsa, "u") != 0) {
Packit Service 31306d
                    return 1;
Packit Service 31306d
                }
Packit Service 31306d
            }
Packit Service 31306d
            break;
Packit Service 31306d
        case SSH_KEYTYPE_ED25519:
Packit Service 31306d
		/* ed25519 keys handled globaly */
Packit Service 31306d
		return 0;
Packit Service 31306d
        case SSH_KEYTYPE_ECDSA_P256:
Packit Service 31306d
        case SSH_KEYTYPE_ECDSA_P384:
Packit Service 31306d
        case SSH_KEYTYPE_ECDSA_P521:
Packit Service 31306d
#ifdef HAVE_GCRYPT_ECC
Packit Service 31306d
            if (k1->ecdsa_nid != k2->ecdsa_nid) {
Packit Service 31306d
                return 1;
Packit Service 31306d
            }
Packit Service 31306d
Packit Service 31306d
            if (_bignum_cmp(k1->ecdsa, k2->ecdsa, "q") != 0) {
Packit Service 31306d
                return 1;
Packit Service 31306d
            }
Packit Service 31306d
Packit Service 31306d
            if (what == SSH_KEY_CMP_PRIVATE) {
Packit Service 31306d
                if (_bignum_cmp(k1->ecdsa, k2->ecdsa, "d") != 0) {
Packit Service 31306d
                    return 1;
Packit Service 31306d
                }
Packit Service 31306d
            }
Packit Service 31306d
            break;
Packit Service 31306d
#endif
Packit Service 31306d
        case SSH_KEYTYPE_DSS_CERT01:
Packit Service 31306d
        case SSH_KEYTYPE_RSA_CERT01:
Packit Service 31306d
        case SSH_KEYTYPE_ECDSA:
Packit Service 31306d
        case SSH_KEYTYPE_ECDSA_P256_CERT01:
Packit Service 31306d
        case SSH_KEYTYPE_ECDSA_P384_CERT01:
Packit Service 31306d
        case SSH_KEYTYPE_ECDSA_P521_CERT01:
Packit Service 31306d
        case SSH_KEYTYPE_ED25519_CERT01:
Packit Service 31306d
        case SSH_KEYTYPE_RSA1:
Packit Service 31306d
        case SSH_KEYTYPE_UNKNOWN:
Packit Service 31306d
            return 1;
Packit Service 31306d
    }
Packit Service 31306d
Packit Service 31306d
    return 0;
Packit Service 31306d
}
Packit Service 31306d
Packit Service 31306d
ssh_string pki_publickey_to_blob(const ssh_key key)
Packit Service 31306d
{
Packit Service 31306d
    ssh_buffer buffer;
Packit Service 31306d
    ssh_string type_s;
Packit Service 31306d
    ssh_string str = NULL;
Packit Service 31306d
    ssh_string e = NULL;
Packit Service 31306d
    ssh_string n = NULL;
Packit Service 31306d
    ssh_string p = NULL;
Packit Service 31306d
    ssh_string g = NULL;
Packit Service 31306d
    ssh_string q = NULL;
Packit Service 31306d
    int rc;
Packit Service 31306d
Packit Service 31306d
    buffer = ssh_buffer_new();
Packit Service 31306d
    if (buffer == NULL) {
Packit Service 31306d
        return NULL;
Packit Service 31306d
    }
Packit Service 31306d
Packit Service 31306d
    if (key->cert != NULL) {
Packit Service 31306d
        rc = ssh_buffer_add_buffer(buffer, key->cert);
Packit Service 31306d
        if (rc < 0) {
Packit Service 31306d
            SSH_BUFFER_FREE(buffer);
Packit Service 31306d
            return NULL;
Packit Service 31306d
        }
Packit Service 31306d
        goto makestring;
Packit Service 31306d
    }
Packit Service 31306d
Packit Service 31306d
    type_s = ssh_string_from_char(key->type_c);
Packit Service 31306d
    if (type_s == NULL) {
Packit Service 31306d
        SSH_BUFFER_FREE(buffer);
Packit Service 31306d
        return NULL;
Packit Service 31306d
    }
Packit Service 31306d
Packit Service 31306d
    rc = ssh_buffer_add_ssh_string(buffer, type_s);
Packit Service 31306d
    SSH_STRING_FREE(type_s);
Packit Service 31306d
    if (rc < 0) {
Packit Service 31306d
        SSH_BUFFER_FREE(buffer);
Packit Service 31306d
        return NULL;
Packit Service 31306d
    }
Packit Service 31306d
Packit Service 31306d
    switch (key->type) {
Packit Service 31306d
        case SSH_KEYTYPE_DSS:
Packit Service 31306d
            p = ssh_sexp_extract_mpi(key->dsa,
Packit Service 31306d
                                     "p",
Packit Service 31306d
                                     GCRYMPI_FMT_USG,
Packit Service 31306d
                                     GCRYMPI_FMT_STD);
Packit Service 31306d
            if (p == NULL) {
Packit Service 31306d
                goto fail;
Packit Service 31306d
            }
Packit Service 31306d
Packit Service 31306d
            q = ssh_sexp_extract_mpi(key->dsa,
Packit Service 31306d
                                     "q",
Packit Service 31306d
                                     GCRYMPI_FMT_USG,
Packit Service 31306d
                                     GCRYMPI_FMT_STD);
Packit Service 31306d
            if (q == NULL) {
Packit Service 31306d
                goto fail;
Packit Service 31306d
            }
Packit Service 31306d
Packit Service 31306d
            g = ssh_sexp_extract_mpi(key->dsa,
Packit Service 31306d
                                     "g",
Packit Service 31306d
                                     GCRYMPI_FMT_USG,
Packit Service 31306d
                                     GCRYMPI_FMT_STD);
Packit Service 31306d
            if (g == NULL) {
Packit Service 31306d
                goto fail;
Packit Service 31306d
            }
Packit Service 31306d
Packit Service 31306d
            n = ssh_sexp_extract_mpi(key->dsa,
Packit Service 31306d
                                     "y",
Packit Service 31306d
                                     GCRYMPI_FMT_USG,
Packit Service 31306d
                                     GCRYMPI_FMT_STD);
Packit Service 31306d
            if (n == NULL) {
Packit Service 31306d
                goto fail;
Packit Service 31306d
            }
Packit Service 31306d
Packit Service 31306d
            rc = ssh_buffer_add_ssh_string(buffer, p);
Packit Service 31306d
            if (rc < 0) {
Packit Service 31306d
                goto fail;
Packit Service 31306d
            }
Packit Service 31306d
            rc = ssh_buffer_add_ssh_string(buffer, q);
Packit Service 31306d
            if (rc < 0) {
Packit Service 31306d
                goto fail;
Packit Service 31306d
            }
Packit Service 31306d
            rc = ssh_buffer_add_ssh_string(buffer, g);
Packit Service 31306d
            if (rc < 0) {
Packit Service 31306d
                goto fail;
Packit Service 31306d
            }
Packit Service 31306d
            rc = ssh_buffer_add_ssh_string(buffer, n);
Packit Service 31306d
            if (rc < 0) {
Packit Service 31306d
                goto fail;
Packit Service 31306d
            }
Packit Service 31306d
Packit Service 31306d
            ssh_string_burn(p);
Packit Service 31306d
            SSH_STRING_FREE(p);
Packit Service 31306d
            ssh_string_burn(g);
Packit Service 31306d
            SSH_STRING_FREE(g);
Packit Service 31306d
            ssh_string_burn(q);
Packit Service 31306d
            SSH_STRING_FREE(q);
Packit Service 31306d
            ssh_string_burn(n);
Packit Service 31306d
            SSH_STRING_FREE(n);
Packit Service 31306d
Packit Service 31306d
            break;
Packit Service 31306d
        case SSH_KEYTYPE_RSA:
Packit Service 31306d
            e = ssh_sexp_extract_mpi(key->rsa,
Packit Service 31306d
                                     "e",
Packit Service 31306d
                                     GCRYMPI_FMT_USG,
Packit Service 31306d
                                     GCRYMPI_FMT_STD);
Packit Service 31306d
            if (e == NULL) {
Packit Service 31306d
                goto fail;
Packit Service 31306d
            }
Packit Service 31306d
Packit Service 31306d
            n = ssh_sexp_extract_mpi(key->rsa,
Packit Service 31306d
                                     "n",
Packit Service 31306d
                                     GCRYMPI_FMT_USG,
Packit Service 31306d
                                     GCRYMPI_FMT_STD);
Packit Service 31306d
            if (n == NULL) {
Packit Service 31306d
                goto fail;
Packit Service 31306d
            }
Packit Service 31306d
Packit Service 31306d
            rc = ssh_buffer_add_ssh_string(buffer, e);
Packit Service 31306d
            if (rc < 0) {
Packit Service 31306d
                goto fail;
Packit Service 31306d
            }
Packit Service 31306d
            rc = ssh_buffer_add_ssh_string(buffer, n);
Packit Service 31306d
            if (rc < 0) {
Packit Service 31306d
                goto fail;
Packit Service 31306d
            }
Packit Service 31306d
Packit Service 31306d
            ssh_string_burn(e);
Packit Service 31306d
            SSH_STRING_FREE(e);
Packit Service 31306d
            ssh_string_burn(n);
Packit Service 31306d
            SSH_STRING_FREE(n);
Packit Service 31306d
Packit Service 31306d
            break;
Packit Service 31306d
        case SSH_KEYTYPE_ED25519:
Packit Service 31306d
		rc = pki_ed25519_public_key_to_blob(buffer, key);
Packit Service 31306d
		if (rc != SSH_OK){
Packit Service 31306d
			goto fail;
Packit Service 31306d
		}
Packit Service 31306d
		break;
Packit Service 31306d
        case SSH_KEYTYPE_ECDSA_P256:
Packit Service 31306d
        case SSH_KEYTYPE_ECDSA_P384:
Packit Service 31306d
        case SSH_KEYTYPE_ECDSA_P521:
Packit Service 31306d
#ifdef HAVE_GCRYPT_ECC
Packit Service 31306d
            type_s = ssh_string_from_char(
Packit Service 31306d
                       pki_key_ecdsa_nid_to_char(key->ecdsa_nid));
Packit Service 31306d
            if (type_s == NULL) {
Packit Service 31306d
                SSH_BUFFER_FREE(buffer);
Packit Service 31306d
                return NULL;
Packit Service 31306d
            }
Packit Service 31306d
Packit Service 31306d
            rc = ssh_buffer_add_ssh_string(buffer, type_s);
Packit Service 31306d
            SSH_STRING_FREE(type_s);
Packit Service 31306d
            if (rc < 0) {
Packit Service 31306d
                SSH_BUFFER_FREE(buffer);
Packit Service 31306d
                return NULL;
Packit Service 31306d
            }
Packit Service 31306d
Packit Service 31306d
            e = ssh_sexp_extract_mpi(key->ecdsa, "q", GCRYMPI_FMT_STD,
Packit Service 31306d
                                     GCRYMPI_FMT_STD);
Packit Service 31306d
            if (e == NULL) {
Packit Service 31306d
                SSH_BUFFER_FREE(buffer);
Packit Service 31306d
                return NULL;
Packit Service 31306d
            }
Packit Service 31306d
Packit Service 31306d
            rc = ssh_buffer_add_ssh_string(buffer, e);
Packit Service 31306d
            if (rc < 0) {
Packit Service 31306d
                goto fail;
Packit Service 31306d
            }
Packit Service 31306d
Packit Service 31306d
            ssh_string_burn(e);
Packit Service 31306d
            SSH_STRING_FREE(e);
Packit Service 31306d
            e = NULL;
Packit Service 31306d
            break;
Packit Service 31306d
#endif
Packit Service 31306d
        case SSH_KEYTYPE_RSA1:
Packit Service 31306d
        case SSH_KEYTYPE_UNKNOWN:
Packit Service 31306d
        default:
Packit Service 31306d
            goto fail;
Packit Service 31306d
    }
Packit Service 31306d
Packit Service 31306d
makestring:
Packit Service 31306d
    str = ssh_string_new(ssh_buffer_get_len(buffer));
Packit Service 31306d
    if (str == NULL) {
Packit Service 31306d
        goto fail;
Packit Service 31306d
    }
Packit Service 31306d
Packit Service 31306d
    rc = ssh_string_fill(str, ssh_buffer_get(buffer), ssh_buffer_get_len(buffer));
Packit Service 31306d
    if (rc < 0) {
Packit Service 31306d
        goto fail;
Packit Service 31306d
    }
Packit Service 31306d
    SSH_BUFFER_FREE(buffer);
Packit Service 31306d
Packit Service 31306d
    return str;
Packit Service 31306d
fail:
Packit Service 31306d
    SSH_BUFFER_FREE(buffer);
Packit Service 31306d
    ssh_string_burn(str);
Packit Service 31306d
    SSH_STRING_FREE(str);
Packit Service 31306d
    ssh_string_burn(e);
Packit Service 31306d
    SSH_STRING_FREE(e);
Packit Service 31306d
    ssh_string_burn(p);
Packit Service 31306d
    SSH_STRING_FREE(p);
Packit Service 31306d
    ssh_string_burn(g);
Packit Service 31306d
    SSH_STRING_FREE(g);
Packit Service 31306d
    ssh_string_burn(q);
Packit Service 31306d
    SSH_STRING_FREE(q);
Packit Service 31306d
    ssh_string_burn(n);
Packit Service 31306d
    SSH_STRING_FREE(n);
Packit Service 31306d
Packit Service 31306d
    return NULL;
Packit Service 31306d
}
Packit Service 31306d
Packit Service 31306d
ssh_string pki_signature_to_blob(const ssh_signature sig)
Packit Service 31306d
{
Packit Service 31306d
    char buffer[40] = { 0 };
Packit Service 31306d
Packit Service 31306d
    const char *r = NULL;
Packit Service 31306d
    size_t r_len, r_offset_in, r_offset_out;
Packit Service 31306d
Packit Service 31306d
    const char *s = NULL;
Packit Service 31306d
    size_t s_len, s_offset_in, s_offset_out;
Packit Service 31306d
Packit Service 31306d
    gcry_sexp_t sexp;
Packit Service 31306d
    size_t size = 0;
Packit Service 31306d
    ssh_string sig_blob = NULL;
Packit Service 31306d
Packit Service 31306d
    switch(sig->type) {
Packit Service 31306d
        case SSH_KEYTYPE_DSS:
Packit Service 31306d
            sexp = gcry_sexp_find_token(sig->dsa_sig, "r", 0);
Packit Service 31306d
            if (sexp == NULL) {
Packit Service 31306d
                return NULL;
Packit Service 31306d
            }
Packit Service 31306d
            r = gcry_sexp_nth_data(sexp, 1, &size);
Packit Service 31306d
            /* libgcrypt put 0 when first bit is set */
Packit Service 31306d
            if (*r == 0) {
Packit Service 31306d
                size--;
Packit Service 31306d
                r++;
Packit Service 31306d
            }
Packit Service 31306d
Packit Service 31306d
            r_len = size;
Packit Service 31306d
            r_offset_in  = (r_len > 20) ? (r_len - 20) : 0;
Packit Service 31306d
            r_offset_out = (r_len < 20) ? (20 - r_len) : 0;
Packit Service 31306d
            memcpy(buffer + r_offset_out,
Packit Service 31306d
                   r + r_offset_in,
Packit Service 31306d
                   r_len - r_offset_in);
Packit Service 31306d
Packit Service 31306d
            gcry_sexp_release(sexp);
Packit Service 31306d
Packit Service 31306d
            sexp = gcry_sexp_find_token(sig->dsa_sig, "s", 0);
Packit Service 31306d
            if (sexp == NULL) {
Packit Service 31306d
                return NULL;
Packit Service 31306d
            }
Packit Service 31306d
            s = gcry_sexp_nth_data(sexp,1,&size);
Packit Service 31306d
            if (*s == 0) {
Packit Service 31306d
                size--;
Packit Service 31306d
                s++;
Packit Service 31306d
            }
Packit Service 31306d
Packit Service 31306d
            s_len = size;
Packit Service 31306d
            s_offset_in  = (s_len > 20) ? (s_len - 20) : 0;
Packit Service 31306d
            s_offset_out = (s_len < 20) ? (20 - s_len) : 0;
Packit Service 31306d
            memcpy(buffer + 20 + s_offset_out,
Packit Service 31306d
                   s + s_offset_in,
Packit Service 31306d
                   s_len - s_offset_in);
Packit Service 31306d
Packit Service 31306d
            gcry_sexp_release(sexp);
Packit Service 31306d
Packit Service 31306d
            sig_blob = ssh_string_new(40);
Packit Service 31306d
            if (sig_blob == NULL) {
Packit Service 31306d
                return NULL;
Packit Service 31306d
            }
Packit Service 31306d
Packit Service 31306d
            ssh_string_fill(sig_blob, buffer, 40);
Packit Service 31306d
            break;
Packit Service 31306d
        case SSH_KEYTYPE_RSA:
Packit Service 31306d
            sexp = gcry_sexp_find_token(sig->rsa_sig, "s", 0);
Packit Service 31306d
            if (sexp == NULL) {
Packit Service 31306d
                return NULL;
Packit Service 31306d
            }
Packit Service 31306d
            s = gcry_sexp_nth_data(sexp, 1, &size);
Packit Service 31306d
            if (*s == 0) {
Packit Service 31306d
                size--;
Packit Service 31306d
                s++;
Packit Service 31306d
            }
Packit Service 31306d
Packit Service 31306d
            sig_blob = ssh_string_new(size);
Packit Service 31306d
            if (sig_blob == NULL) {
Packit Service 31306d
                return NULL;
Packit Service 31306d
            }
Packit Service 31306d
            ssh_string_fill(sig_blob, discard_const_p(char, s), size);
Packit Service 31306d
Packit Service 31306d
            gcry_sexp_release(sexp);
Packit Service 31306d
            break;
Packit Service 31306d
        case SSH_KEYTYPE_ED25519:
Packit Service 31306d
		sig_blob = pki_ed25519_signature_to_blob(sig);
Packit Service 31306d
		break;
Packit Service 31306d
        case SSH_KEYTYPE_ECDSA_P256:
Packit Service 31306d
        case SSH_KEYTYPE_ECDSA_P384:
Packit Service 31306d
        case SSH_KEYTYPE_ECDSA_P521:
Packit Service 31306d
#ifdef HAVE_GCRYPT_ECC
Packit Service 31306d
            {
Packit Service 31306d
                ssh_string R;
Packit Service 31306d
                ssh_string S;
Packit Service 31306d
                ssh_buffer b;
Packit Service 31306d
                int rc;
Packit Service 31306d
Packit Service 31306d
                b = ssh_buffer_new();
Packit Service 31306d
                if (b == NULL) {
Packit Service 31306d
                    return NULL;
Packit Service 31306d
                }
Packit Service 31306d
Packit Service 31306d
                R = ssh_sexp_extract_mpi(sig->ecdsa_sig, "r",
Packit Service 31306d
                                         GCRYMPI_FMT_USG, GCRYMPI_FMT_STD);
Packit Service 31306d
                if (R == NULL) {
Packit Service 31306d
                    SSH_BUFFER_FREE(b);
Packit Service 31306d
                    return NULL;
Packit Service 31306d
                }
Packit Service 31306d
Packit Service 31306d
                rc = ssh_buffer_add_ssh_string(b, R);
Packit Service 31306d
                SSH_STRING_FREE(R);
Packit Service 31306d
                if (rc < 0) {
Packit Service 31306d
                    SSH_BUFFER_FREE(b);
Packit Service 31306d
                    return NULL;
Packit Service 31306d
                }
Packit Service 31306d
Packit Service 31306d
                S = ssh_sexp_extract_mpi(sig->ecdsa_sig, "s",
Packit Service 31306d
                                         GCRYMPI_FMT_USG, GCRYMPI_FMT_STD);
Packit Service 31306d
                if (S == NULL) {
Packit Service 31306d
                    SSH_BUFFER_FREE(b);
Packit Service 31306d
                    return NULL;
Packit Service 31306d
                }
Packit Service 31306d
Packit Service 31306d
                rc = ssh_buffer_add_ssh_string(b, S);
Packit Service 31306d
                SSH_STRING_FREE(S);
Packit Service 31306d
                if (rc < 0) {
Packit Service 31306d
                    SSH_BUFFER_FREE(b);
Packit Service 31306d
                    return NULL;
Packit Service 31306d
                }
Packit Service 31306d
Packit Service 31306d
                sig_blob = ssh_string_new(ssh_buffer_get_len(b));
Packit Service 31306d
                if (sig_blob == NULL) {
Packit Service 31306d
                    SSH_BUFFER_FREE(b);
Packit Service 31306d
                    return NULL;
Packit Service 31306d
                }
Packit Service 31306d
Packit Service 31306d
                ssh_string_fill(sig_blob,
Packit Service 31306d
                                ssh_buffer_get(b), ssh_buffer_get_len(b));
Packit Service 31306d
                SSH_BUFFER_FREE(b);
Packit Service 31306d
                break;
Packit Service 31306d
            }
Packit Service 31306d
#endif
Packit Service 31306d
        case SSH_KEYTYPE_RSA1:
Packit Service 31306d
        case SSH_KEYTYPE_UNKNOWN:
Packit Service 31306d
        default:
Packit Service 31306d
            SSH_LOG(SSH_LOG_WARN, "Unknown signature key type: %d", sig->type);
Packit Service 31306d
            return NULL;
Packit Service 31306d
            break;
Packit Service 31306d
    }
Packit Service 31306d
Packit Service 31306d
    return sig_blob;
Packit Service 31306d
}
Packit Service 31306d
Packit Service 31306d
ssh_signature pki_signature_from_blob(const ssh_key pubkey,
Packit Service 31306d
                                      const ssh_string sig_blob,
Packit Service 31306d
                                      enum ssh_keytypes_e type,
Packit Service 31306d
                                      enum ssh_digest_e hash_type)
Packit Service 31306d
{
Packit Service 31306d
    ssh_signature sig;
Packit Service 31306d
    gcry_error_t err;
Packit Service 31306d
    size_t len;
Packit Service 31306d
    size_t rsalen;
Packit Service 31306d
    int rc;
Packit Service 31306d
Packit Service 31306d
    if (ssh_key_type_plain(pubkey->type) != type) {
Packit Service 31306d
        SSH_LOG(SSH_LOG_WARN,
Packit Service 31306d
                "Incompatible public key provided (%d) expecting (%d)",
Packit Service 31306d
                type,
Packit Service 31306d
                pubkey->type);
Packit Service 31306d
        return NULL;
Packit Service 31306d
    }
Packit Service 31306d
Packit Service 31306d
    sig = ssh_signature_new();
Packit Service 31306d
    if (sig == NULL) {
Packit Service 31306d
        return NULL;
Packit Service 31306d
    }
Packit Service 31306d
Packit Service 31306d
    sig->type = type;
Packit Service 31306d
    sig->type_c = ssh_key_signature_to_char(type, hash_type);
Packit Service 31306d
    sig->hash_type = hash_type;
Packit Service 31306d
Packit Service 31306d
    len = ssh_string_len(sig_blob);
Packit Service 31306d
Packit Service 31306d
    switch(type) {
Packit Service 31306d
        case SSH_KEYTYPE_DSS:
Packit Service 31306d
            /* 40 is the dual signature blob len. */
Packit Service 31306d
            if (len != 40) {
Packit Service 31306d
                SSH_LOG(SSH_LOG_WARN,
Packit Service 31306d
                        "Signature has wrong size: %lu",
Packit Service 31306d
                        (unsigned long)len);
Packit Service 31306d
                ssh_signature_free(sig);
Packit Service 31306d
                return NULL;
Packit Service 31306d
            }
Packit Service 31306d
Packit Service 31306d
#ifdef DEBUG_CRYPTO
Packit Service 31306d
            SSH_LOG(SSH_LOG_DEBUG,
Packit Service 31306d
                    "DSA signature len: %lu",
Packit Service 31306d
                    (unsigned long)len);
Packit Service 31306d
            ssh_log_hexdump("DSA signature", ssh_string_data(sig_blob), len);
Packit Service 31306d
#endif
Packit Service 31306d
Packit Service 31306d
            err = gcry_sexp_build(&sig->dsa_sig,
Packit Service 31306d
                                  NULL,
Packit Service 31306d
                                  "(sig-val(dsa(r %b)(s %b)))",
Packit Service 31306d
                                  20,
Packit Service 31306d
                                  ssh_string_data(sig_blob),
Packit Service 31306d
                                  20,
Packit Service 31306d
                                  (unsigned char *)ssh_string_data(sig_blob) + 20);
Packit Service 31306d
            if (err) {
Packit Service 31306d
                ssh_signature_free(sig);
Packit Service 31306d
                return NULL;
Packit Service 31306d
            }
Packit Service 31306d
            break;
Packit Service 31306d
        case SSH_KEYTYPE_RSA:
Packit Service 31306d
            rsalen = (gcry_pk_get_nbits(pubkey->rsa) + 7) / 8;
Packit Service 31306d
Packit Service 31306d
            if (len > rsalen) {
Packit Service 31306d
                SSH_LOG(SSH_LOG_WARN,
Packit Service 31306d
                        "Signature is to big size: %lu",
Packit Service 31306d
                        (unsigned long)len);
Packit Service 31306d
                ssh_signature_free(sig);
Packit Service 31306d
                return NULL;
Packit Service 31306d
            }
Packit Service 31306d
Packit Service 31306d
            if (len < rsalen) {
Packit Service 31306d
                SSH_LOG(SSH_LOG_DEBUG,
Packit Service 31306d
                        "RSA signature len %lu < %lu",
Packit Service 31306d
                        (unsigned long)len,
Packit Service 31306d
                        (unsigned long)rsalen);
Packit Service 31306d
            }
Packit Service 31306d
Packit Service 31306d
#ifdef DEBUG_CRYPTO
Packit Service 31306d
            SSH_LOG(SSH_LOG_DEBUG, "RSA signature len: %lu", (unsigned long)len);
Packit Service 31306d
            ssh_log_hexdump("RSA signature", ssh_string_data(sig_blob), len);
Packit Service 31306d
#endif
Packit Service 31306d
Packit Service 31306d
            err = gcry_sexp_build(&sig->rsa_sig,
Packit Service 31306d
                                  NULL,
Packit Service 31306d
                                  "(sig-val(rsa(s %b)))",
Packit Service 31306d
                                  ssh_string_len(sig_blob),
Packit Service 31306d
                                  ssh_string_data(sig_blob));
Packit Service 31306d
            if (err) {
Packit Service 31306d
                ssh_signature_free(sig);
Packit Service 31306d
                return NULL;
Packit Service 31306d
            }
Packit Service 31306d
            break;
Packit Service 31306d
        case SSH_KEYTYPE_ED25519:
Packit Service 31306d
		rc = pki_signature_from_ed25519_blob(sig, sig_blob);
Packit Service 31306d
		if (rc != SSH_OK){
Packit Service 31306d
			ssh_signature_free(sig);
Packit Service 31306d
			return NULL;
Packit Service 31306d
		}
Packit Service 31306d
		break;
Packit Service 31306d
        case SSH_KEYTYPE_ECDSA_P256:
Packit Service 31306d
        case SSH_KEYTYPE_ECDSA_P384:
Packit Service 31306d
        case SSH_KEYTYPE_ECDSA_P521:
Packit Service 31306d
#ifdef HAVE_GCRYPT_ECC
Packit Service 31306d
            { /* build ecdsa siganature */
Packit Service 31306d
                ssh_buffer b;
Packit Service 31306d
                ssh_string r, s;
Packit Service 31306d
                uint32_t rlen;
Packit Service 31306d
Packit Service 31306d
                b = ssh_buffer_new();
Packit Service 31306d
                if (b == NULL) {
Packit Service 31306d
                    ssh_signature_free(sig);
Packit Service 31306d
                    return NULL;
Packit Service 31306d
                }
Packit Service 31306d
Packit Service 31306d
                rc = ssh_buffer_add_data(b,
Packit Service 31306d
                                         ssh_string_data(sig_blob),
Packit Service 31306d
                                         ssh_string_len(sig_blob));
Packit Service 31306d
                if (rc < 0) {
Packit Service 31306d
                    SSH_BUFFER_FREE(b);
Packit Service 31306d
                    ssh_signature_free(sig);
Packit Service 31306d
                    return NULL;
Packit Service 31306d
                }
Packit Service 31306d
Packit Service 31306d
                r = ssh_buffer_get_ssh_string(b);
Packit Service 31306d
                if (r == NULL) {
Packit Service 31306d
                    SSH_BUFFER_FREE(b);
Packit Service 31306d
                    ssh_signature_free(sig);
Packit Service 31306d
                    return NULL;
Packit Service 31306d
                }
Packit Service 31306d
Packit Service 31306d
                s = ssh_buffer_get_ssh_string(b);
Packit Service 31306d
                rlen = ssh_buffer_get_len(b);
Packit Service 31306d
                SSH_BUFFER_FREE(b);
Packit Service 31306d
                if (s == NULL) {
Packit Service 31306d
                    ssh_string_burn(r);
Packit Service 31306d
                    SSH_STRING_FREE(r);
Packit Service 31306d
                    ssh_signature_free(sig);
Packit Service 31306d
                    return NULL;
Packit Service 31306d
                }
Packit Service 31306d
Packit Service 31306d
                if (rlen != 0) {
Packit Service 31306d
                    SSH_LOG(SSH_LOG_WARN,
Packit Service 31306d
                            "Signature has remaining bytes in inner "
Packit Service 31306d
                            "sigblob: %lu",
Packit Service 31306d
                            (unsigned long)rlen);
Packit Service 31306d
                    ssh_string_burn(r);
Packit Service 31306d
                    SSH_STRING_FREE(r);
Packit Service 31306d
                    ssh_string_burn(s);
Packit Service 31306d
                    SSH_STRING_FREE(s);
Packit Service 31306d
                    ssh_signature_free(sig);
Packit Service 31306d
                    return NULL;
Packit Service 31306d
                }
Packit Service 31306d
Packit Service 31306d
#ifdef DEBUG_CRYPTO
Packit Service 31306d
                ssh_log_hexdump("r", ssh_string_data(r), ssh_string_len(r));
Packit Service 31306d
                ssh_log_hexdump("s", ssh_string_data(s), ssh_string_len(s));
Packit Service 31306d
#endif
Packit Service 31306d
Packit Service 31306d
                err = gcry_sexp_build(&sig->ecdsa_sig,
Packit Service 31306d
                                      NULL,
Packit Service 31306d
                                      "(sig-val(ecdsa(r %b)(s %b)))",
Packit Service 31306d
                                      ssh_string_len(r),
Packit Service 31306d
                                      ssh_string_data(r),
Packit Service 31306d
                                      ssh_string_len(s),
Packit Service 31306d
                                      ssh_string_data(s));
Packit Service 31306d
                ssh_string_burn(r);
Packit Service 31306d
                SSH_STRING_FREE(r);
Packit Service 31306d
                ssh_string_burn(s);
Packit Service 31306d
                SSH_STRING_FREE(s);
Packit Service 31306d
                if (err) {
Packit Service 31306d
                    ssh_signature_free(sig);
Packit Service 31306d
                    return NULL;
Packit Service 31306d
                }
Packit Service 31306d
            }
Packit Service 31306d
            break;
Packit Service 31306d
#endif
Packit Service 31306d
        case SSH_KEYTYPE_RSA1:
Packit Service 31306d
        case SSH_KEYTYPE_UNKNOWN:
Packit Service 31306d
        default:
Packit Service 31306d
            SSH_LOG(SSH_LOG_WARN, "Unknown signature type");
Packit Service 31306d
            return NULL;
Packit Service 31306d
    }
Packit Service 31306d
Packit Service 31306d
    return sig;
Packit Service 31306d
}
Packit Service 31306d
Packit Service 31306d
ssh_signature pki_do_sign_hash(const ssh_key privkey,
Packit Service 31306d
                               const unsigned char *hash,
Packit Service 31306d
                               size_t hlen,
Packit Service 31306d
                               enum ssh_digest_e hash_type)
Packit Service 31306d
{
Packit Service 31306d
    unsigned char ghash[hlen + 1];
Packit Service 31306d
    const char *hash_c = NULL;
Packit Service 31306d
    ssh_signature sig;
Packit Service 31306d
    gcry_sexp_t sexp;
Packit Service 31306d
    gcry_error_t err;
Packit Service 31306d
Packit Service 31306d
    sig = ssh_signature_new();
Packit Service 31306d
    if (sig == NULL) {
Packit Service 31306d
        return NULL;
Packit Service 31306d
    }
Packit Service 31306d
    sig->type = privkey->type;
Packit Service 31306d
    sig->type_c = ssh_key_signature_to_char(privkey->type, hash_type);
Packit Service 31306d
    sig->hash_type = hash_type;
Packit Service 31306d
    switch (privkey->type) {
Packit Service 31306d
        case SSH_KEYTYPE_DSS:
Packit Service 31306d
            /* That is to mark the number as positive */
Packit Service 31306d
            if(hash[0] >= 0x80) {
Packit Service 31306d
                memcpy(ghash + 1, hash, hlen);
Packit Service 31306d
                ghash[0] = 0;
Packit Service 31306d
                hash = ghash;
Packit Service 31306d
                hlen += 1;
Packit Service 31306d
            }
Packit Service 31306d
Packit Service 31306d
            err = gcry_sexp_build(&sexp, NULL, "%b", hlen, hash);
Packit Service 31306d
            if (err) {
Packit Service 31306d
                ssh_signature_free(sig);
Packit Service 31306d
                return NULL;
Packit Service 31306d
            }
Packit Service 31306d
Packit Service 31306d
            err = gcry_pk_sign(&sig->dsa_sig, sexp, privkey->dsa);
Packit Service 31306d
            gcry_sexp_release(sexp);
Packit Service 31306d
            if (err) {
Packit Service 31306d
                ssh_signature_free(sig);
Packit Service 31306d
                return NULL;
Packit Service 31306d
            }
Packit Service 31306d
            break;
Packit Service 31306d
        case SSH_KEYTYPE_RSA:
Packit Service 31306d
            switch (hash_type) {
Packit Service 31306d
            case SSH_DIGEST_SHA1:
Packit Service 31306d
                hash_c = "sha1";
Packit Service 31306d
                break;
Packit Service 31306d
            case SSH_DIGEST_SHA256:
Packit Service 31306d
                hash_c = "sha256";
Packit Service 31306d
                break;
Packit Service 31306d
            case SSH_DIGEST_SHA512:
Packit Service 31306d
                hash_c = "sha512";
Packit Service 31306d
                break;
Packit Service 31306d
            case SSH_DIGEST_AUTO:
Packit Service 31306d
            default:
Packit Service 31306d
                SSH_LOG(SSH_LOG_WARN, "Incompatible key algorithm");
Packit Service 31306d
                return NULL;
Packit Service 31306d
            }
Packit Service 31306d
            err = gcry_sexp_build(&sexp,
Packit Service 31306d
                                  NULL,
Packit Service 31306d
                                  "(data(flags pkcs1)(hash %s %b))",
Packit Service 31306d
                                  hash_c,
Packit Service 31306d
                                  hlen,
Packit Service 31306d
                                  hash);
Packit Service 31306d
            if (err) {
Packit Service 31306d
                ssh_signature_free(sig);
Packit Service 31306d
                return NULL;
Packit Service 31306d
            }
Packit Service 31306d
Packit Service 31306d
            err = gcry_pk_sign(&sig->rsa_sig, sexp, privkey->rsa);
Packit Service 31306d
            gcry_sexp_release(sexp);
Packit Service 31306d
            if (err) {
Packit Service 31306d
                ssh_signature_free(sig);
Packit Service 31306d
                return NULL;
Packit Service 31306d
            }
Packit Service 31306d
            break;
Packit Service 31306d
        case SSH_KEYTYPE_ED25519:
Packit Service 31306d
		err = pki_ed25519_sign(privkey, sig, hash, hlen);
Packit Service 31306d
		if (err != SSH_OK){
Packit Service 31306d
			ssh_signature_free(sig);
Packit Service 31306d
			return NULL;
Packit Service 31306d
		}
Packit Service 31306d
		break;
Packit Service 31306d
        case SSH_KEYTYPE_ECDSA_P256:
Packit Service 31306d
        case SSH_KEYTYPE_ECDSA_P384:
Packit Service 31306d
        case SSH_KEYTYPE_ECDSA_P521:
Packit Service 31306d
#ifdef HAVE_GCRYPT_ECC
Packit Service 31306d
            err = gcry_sexp_build(&sexp,
Packit Service 31306d
                                  NULL,
Packit Service 31306d
                                  "(data(flags raw)(value %b))",
Packit Service 31306d
                                  hlen,
Packit Service 31306d
                                  hash);
Packit Service 31306d
            if (err) {
Packit Service 31306d
                ssh_signature_free(sig);
Packit Service 31306d
                return NULL;
Packit Service 31306d
            }
Packit Service 31306d
Packit Service 31306d
            err = gcry_pk_sign(&sig->ecdsa_sig, sexp, privkey->ecdsa);
Packit Service 31306d
            gcry_sexp_release(sexp);
Packit Service 31306d
            if (err) {
Packit Service 31306d
                ssh_signature_free(sig);
Packit Service 31306d
                return NULL;
Packit Service 31306d
            }
Packit Service 31306d
            break;
Packit Service 31306d
#endif
Packit Service 31306d
        case SSH_KEYTYPE_RSA1:
Packit Service 31306d
        case SSH_KEYTYPE_UNKNOWN:
Packit Service 31306d
        default:
Packit Service 31306d
            ssh_signature_free(sig);
Packit Service 31306d
            return NULL;
Packit Service 31306d
    }
Packit Service 31306d
Packit Service 31306d
    return sig;
Packit Service 31306d
}
Packit Service 31306d
Packit Service 31306d
/**
Packit Service 31306d
 * @internal
Packit Service 31306d
 *
Packit Service 31306d
 * @brief Sign the given input data. The digest of to be signed is calculated
Packit Service 31306d
 * internally as necessary.
Packit Service 31306d
 *
Packit Service 31306d
 * @param[in]   privkey     The private key to be used for signing.
Packit Service 31306d
 * @param[in]   hash_type   The digest algorithm to be used.
Packit Service 31306d
 * @param[in]   input       The data to be signed.
Packit Service 31306d
 * @param[in]   input_len   The length of the data to be signed.
Packit Service 31306d
 *
Packit Service 31306d
 * @return  a newly allocated ssh_signature or NULL on error.
Packit Service 31306d
 */
Packit Service 31306d
ssh_signature pki_sign_data(const ssh_key privkey,
Packit Service 31306d
                            enum ssh_digest_e hash_type,
Packit Service 31306d
                            const unsigned char *input,
Packit Service 31306d
                            size_t input_len)
Packit Service 31306d
{
Packit Service 31306d
    unsigned char hash[SHA512_DIGEST_LEN] = {0};
Packit Service 31306d
    const unsigned char *sign_input = NULL;
Packit Service 31306d
    uint32_t hlen = 0;
Packit Service 31306d
    int rc;
Packit Service 31306d
Packit Service 31306d
    if (privkey == NULL || !ssh_key_is_private(privkey) || input == NULL) {
Packit Service 31306d
        SSH_LOG(SSH_LOG_TRACE, "Bad parameter provided to "
Packit Service 31306d
                               "pki_sign_data()");
Packit Service 31306d
        return NULL;
Packit Service 31306d
    }
Packit Service 31306d
Packit Service 31306d
    /* Check if public key and hash type are compatible */
Packit Service 31306d
    rc = pki_key_check_hash_compatible(privkey, hash_type);
Packit Service 31306d
    if (rc != SSH_OK) {
Packit Service 31306d
        return NULL;
Packit Service 31306d
    }
Packit Service 31306d
Packit Service 31306d
    switch (hash_type) {
Packit Service 31306d
    case SSH_DIGEST_SHA256:
Packit Service 31306d
        sha256(input, input_len, hash);
Packit Service 31306d
        hlen = SHA256_DIGEST_LEN;
Packit Service 31306d
        sign_input = hash;
Packit Service 31306d
        break;
Packit Service 31306d
    case SSH_DIGEST_SHA384:
Packit Service 31306d
        sha384(input, input_len, hash);
Packit Service 31306d
        hlen = SHA384_DIGEST_LEN;
Packit Service 31306d
        sign_input = hash;
Packit Service 31306d
        break;
Packit Service 31306d
    case SSH_DIGEST_SHA512:
Packit Service 31306d
        sha512(input, input_len, hash);
Packit Service 31306d
        hlen = SHA512_DIGEST_LEN;
Packit Service 31306d
        sign_input = hash;
Packit Service 31306d
        break;
Packit Service 31306d
    case SSH_DIGEST_SHA1:
Packit Service 31306d
        sha1(input, input_len, hash);
Packit Service 31306d
        hlen = SHA_DIGEST_LEN;
Packit Service 31306d
        sign_input = hash;
Packit Service 31306d
        break;
Packit Service 31306d
    case SSH_DIGEST_AUTO:
Packit Service 31306d
        if (privkey->type == SSH_KEYTYPE_ED25519) {
Packit Service 31306d
            /* SSH_DIGEST_AUTO should only be used with ed25519 */
Packit Service 31306d
            sign_input = input;
Packit Service 31306d
            hlen = input_len;
Packit Service 31306d
            break;
Packit Service 31306d
        }
Packit Service 31306d
        FALL_THROUGH;
Packit Service 31306d
    default:
Packit Service 31306d
        SSH_LOG(SSH_LOG_TRACE, "Unknown hash algorithm for type: %d",
Packit Service 31306d
                hash_type);
Packit Service 31306d
        return NULL;
Packit Service 31306d
    }
Packit Service 31306d
Packit Service 31306d
    return pki_do_sign_hash(privkey, sign_input, hlen, hash_type);
Packit Service 31306d
}
Packit Service 31306d
Packit Service 31306d
/**
Packit Service 31306d
 * @internal
Packit Service 31306d
 *
Packit Service 31306d
 * @brief Verify the signature of a given input. The digest of the input is
Packit Service 31306d
 * calculated internally as necessary.
Packit Service 31306d
 *
Packit Service 31306d
 * @param[in]   signature   The signature to be verified.
Packit Service 31306d
 * @param[in]   pubkey      The public key used to verify the signature.
Packit Service 31306d
 * @param[in]   input       The signed data.
Packit Service 31306d
 * @param[in]   input_len   The length of the signed data.
Packit Service 31306d
 *
Packit Service 31306d
 * @return  SSH_OK if the signature is valid; SSH_ERROR otherwise.
Packit Service 31306d
 */
Packit Service 31306d
int pki_verify_data_signature(ssh_signature signature,
Packit Service 31306d
                              const ssh_key pubkey,
Packit Service 31306d
                              const unsigned char *input,
Packit Service 31306d
                              size_t input_len)
Packit Service 31306d
{
Packit Service 31306d
    const char *hash_type = NULL;
Packit Service 31306d
    gcry_sexp_t sexp;
Packit Service 31306d
    gcry_error_t err;
Packit Service 31306d
Packit Service 31306d
    unsigned char ghash[SHA512_DIGEST_LEN + 1] = {0};
Packit Service 31306d
    unsigned char *hash = ghash + 1;
Packit Service 31306d
    uint32_t hlen = 0;
Packit Service 31306d
Packit Service 31306d
    const unsigned char *verify_input = NULL;
Packit Service 31306d
Packit Service 31306d
    int rc;
Packit Service 31306d
Packit Service 31306d
    if (pubkey == NULL || ssh_key_is_private(pubkey) || input == NULL ||
Packit Service 31306d
        signature == NULL)
Packit Service 31306d
    {
Packit Service 31306d
        SSH_LOG(SSH_LOG_TRACE, "Bad parameter provided to "
Packit Service 31306d
                               "pki_verify_data_signature()");
Packit Service 31306d
        return SSH_ERROR;
Packit Service 31306d
    }
Packit Service 31306d
Packit Service 31306d
    /* Check if public key and hash type are compatible */
Packit Service 31306d
    rc = pki_key_check_hash_compatible(pubkey, signature->hash_type);
Packit Service 31306d
    if (rc != SSH_OK) {
Packit Service 31306d
        return SSH_ERROR;
Packit Service 31306d
    }
Packit Service 31306d
Packit Service 31306d
    switch (signature->hash_type) {
Packit Service 31306d
    case SSH_DIGEST_SHA256:
Packit Service 31306d
        sha256(input, input_len, hash);
Packit Service 31306d
        hlen = SHA256_DIGEST_LEN;
Packit Service 31306d
        hash_type = "sha256";
Packit Service 31306d
        verify_input = hash;
Packit Service 31306d
        break;
Packit Service 31306d
    case SSH_DIGEST_SHA384:
Packit Service 31306d
        sha384(input, input_len, hash);
Packit Service 31306d
        hlen = SHA384_DIGEST_LEN;
Packit Service 31306d
        hash_type = "sha384";
Packit Service 31306d
        verify_input = hash;
Packit Service 31306d
        break;
Packit Service 31306d
    case SSH_DIGEST_SHA512:
Packit Service 31306d
        sha512(input, input_len, hash);
Packit Service 31306d
        hlen = SHA512_DIGEST_LEN;
Packit Service 31306d
        hash_type = "sha512";
Packit Service 31306d
        verify_input = hash;
Packit Service 31306d
        break;
Packit Service 31306d
    case SSH_DIGEST_SHA1:
Packit Service 31306d
        sha1(input, input_len, hash);
Packit Service 31306d
        hlen = SHA_DIGEST_LEN;
Packit Service 31306d
        hash_type = "sha1";
Packit Service 31306d
        verify_input = hash;
Packit Service 31306d
        break;
Packit Service 31306d
    case SSH_DIGEST_AUTO:
Packit Service 31306d
        if (pubkey->type == SSH_KEYTYPE_ED25519 ||
Packit Service 31306d
            pubkey->type == SSH_KEYTYPE_ED25519_CERT01)
Packit Service 31306d
        {
Packit Service 31306d
            verify_input = input;
Packit Service 31306d
            hlen = input_len;
Packit Service 31306d
            break;
Packit Service 31306d
        }
Packit Service 31306d
        FALL_THROUGH;
Packit Service 31306d
    default:
Packit Service 31306d
        SSH_LOG(SSH_LOG_TRACE, "Unknown sig->hash_type: %d", signature->hash_type);
Packit Service 31306d
        return SSH_ERROR;
Packit Service 31306d
    }
Packit Service 31306d
Packit Service 31306d
    switch(pubkey->type) {
Packit Service 31306d
        case SSH_KEYTYPE_DSS:
Packit Service 31306d
        case SSH_KEYTYPE_DSS_CERT01:
Packit Service 31306d
            /* That is to mark the number as positive */
Packit Service 31306d
            if(hash[0] >= 0x80) {
Packit Service 31306d
                hash = ghash;
Packit Service 31306d
                hlen += 1;
Packit Service 31306d
            }
Packit Service 31306d
Packit Service 31306d
            err = gcry_sexp_build(&sexp, NULL, "%b", hlen, hash);
Packit Service 31306d
            if (err) {
Packit Service 31306d
                SSH_LOG(SSH_LOG_TRACE,
Packit Service 31306d
                        "DSA hash error: %s", gcry_strerror(err));
Packit Service 31306d
                return SSH_ERROR;
Packit Service 31306d
            }
Packit Service 31306d
            err = gcry_pk_verify(signature->dsa_sig, sexp, pubkey->dsa);
Packit Service 31306d
            gcry_sexp_release(sexp);
Packit Service 31306d
            if (err) {
Packit Service 31306d
                SSH_LOG(SSH_LOG_TRACE, "Invalid DSA signature");
Packit Service 31306d
                if (gcry_err_code(err) != GPG_ERR_BAD_SIGNATURE) {
Packit Service 31306d
                    SSH_LOG(SSH_LOG_TRACE,
Packit Service 31306d
                            "DSA verify error: %s",
Packit Service 31306d
                            gcry_strerror(err));
Packit Service 31306d
                }
Packit Service 31306d
                return SSH_ERROR;
Packit Service 31306d
            }
Packit Service 31306d
            break;
Packit Service 31306d
        case SSH_KEYTYPE_RSA:
Packit Service 31306d
        case SSH_KEYTYPE_RSA_CERT01:
Packit Service 31306d
            err = gcry_sexp_build(&sexp,
Packit Service 31306d
                                  NULL,
Packit Service 31306d
                                  "(data(flags pkcs1)(hash %s %b))",
Packit Service 31306d
                                  hash_type, hlen, hash);
Packit Service 31306d
            if (err) {
Packit Service 31306d
                SSH_LOG(SSH_LOG_TRACE,
Packit Service 31306d
                              "RSA hash error: %s",
Packit Service 31306d
                              gcry_strerror(err));
Packit Service 31306d
                return SSH_ERROR;
Packit Service 31306d
            }
Packit Service 31306d
            err = gcry_pk_verify(signature->rsa_sig, sexp, pubkey->rsa);
Packit Service 31306d
            gcry_sexp_release(sexp);
Packit Service 31306d
            if (err) {
Packit Service 31306d
                SSH_LOG(SSH_LOG_TRACE, "Invalid RSA signature");
Packit Service 31306d
                if (gcry_err_code(err) != GPG_ERR_BAD_SIGNATURE) {
Packit Service 31306d
                    SSH_LOG(SSH_LOG_TRACE,
Packit Service 31306d
                            "RSA verify error: %s",
Packit Service 31306d
                            gcry_strerror(err));
Packit Service 31306d
                }
Packit Service 31306d
                return SSH_ERROR;
Packit Service 31306d
            }
Packit Service 31306d
            break;
Packit Service 31306d
        case SSH_KEYTYPE_ECDSA_P256:
Packit Service 31306d
        case SSH_KEYTYPE_ECDSA_P384:
Packit Service 31306d
        case SSH_KEYTYPE_ECDSA_P521:
Packit Service 31306d
        case SSH_KEYTYPE_ECDSA_P256_CERT01:
Packit Service 31306d
        case SSH_KEYTYPE_ECDSA_P384_CERT01:
Packit Service 31306d
        case SSH_KEYTYPE_ECDSA_P521_CERT01:
Packit Service 31306d
#ifdef HAVE_GCRYPT_ECC
Packit Service 31306d
            err = gcry_sexp_build(&sexp,
Packit Service 31306d
                                  NULL,
Packit Service 31306d
                                  "(data(flags raw)(value %b))",
Packit Service 31306d
                                  hlen,
Packit Service 31306d
                                  hash);
Packit Service 31306d
            if (err) {
Packit Service 31306d
                SSH_LOG(SSH_LOG_TRACE,
Packit Service 31306d
                        "ECDSA hash error: %s",
Packit Service 31306d
                        gcry_strerror(err));
Packit Service 31306d
                return SSH_ERROR;
Packit Service 31306d
            }
Packit Service 31306d
            err = gcry_pk_verify(signature->ecdsa_sig, sexp, pubkey->ecdsa);
Packit Service 31306d
            gcry_sexp_release(sexp);
Packit Service 31306d
            if (err) {
Packit Service 31306d
                SSH_LOG(SSH_LOG_TRACE, "Invalid ECDSA signature");
Packit Service 31306d
                if (gcry_err_code(err) != GPG_ERR_BAD_SIGNATURE) {
Packit Service 31306d
                    SSH_LOG(SSH_LOG_TRACE,
Packit Service 31306d
                            "ECDSA verify error: %s",
Packit Service 31306d
                            gcry_strerror(err));
Packit Service 31306d
                }
Packit Service 31306d
                return SSH_ERROR;
Packit Service 31306d
            }
Packit Service 31306d
            break;
Packit Service 31306d
#endif
Packit Service 31306d
        case SSH_KEYTYPE_ED25519:
Packit Service 31306d
        case SSH_KEYTYPE_ED25519_CERT01:
Packit Service 31306d
            rc = pki_ed25519_verify(pubkey, signature, verify_input, hlen);
Packit Service 31306d
            if (rc != SSH_OK) {
Packit Service 31306d
                SSH_LOG(SSH_LOG_TRACE, "ED25519 error: Signature invalid");
Packit Service 31306d
                return SSH_ERROR;
Packit Service 31306d
            }
Packit Service 31306d
            break;
Packit Service 31306d
        case SSH_KEYTYPE_RSA1:
Packit Service 31306d
        case SSH_KEYTYPE_UNKNOWN:
Packit Service 31306d
        default:
Packit Service 31306d
            SSH_LOG(SSH_LOG_TRACE, "Unknown public key type");
Packit Service 31306d
            return SSH_ERROR;
Packit Service 31306d
    }
Packit Service 31306d
Packit Service 31306d
    return SSH_OK;
Packit Service 31306d
}
Packit Service 31306d
Packit Service 31306d
#endif /* HAVE_LIBGCRYPT */