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

Diff for /src/usr.bin/ssh/ssh-ecdsa.c between version 1.10 and 1.11

version 1.10, 2014/02/03 23:28:00 version 1.11, 2014/06/24 01:13:21
Line 33 
Line 33 
   
 #include <string.h>  #include <string.h>
   
 #include "xmalloc.h"  #include "sshbuf.h"
 #include "buffer.h"  #include "ssherr.h"
 #include "compat.h"  
 #include "log.h"  
 #include "key.h"  
 #include "digest.h"  #include "digest.h"
   #define SSHKEY_INTERNAL
   #include "sshkey.h"
   
   /* ARGSUSED */
 int  int
 ssh_ecdsa_sign(const Key *key, u_char **sigp, u_int *lenp,  ssh_ecdsa_sign(const struct sshkey *key, u_char **sigp, size_t *lenp,
     const u_char *data, u_int datalen)      const u_char *data, size_t datalen, u_int compat)
 {  {
         ECDSA_SIG *sig;          ECDSA_SIG *sig = NULL;
         int hash_alg;          int hash_alg;
         u_char digest[SSH_DIGEST_MAX_LENGTH];          u_char digest[SSH_DIGEST_MAX_LENGTH];
         u_int len, dlen;          size_t len, dlen;
         Buffer b, bb;          struct sshbuf *b = NULL, *bb = NULL;
           int ret = SSH_ERR_INTERNAL_ERROR;
   
         if (key == NULL || key_type_plain(key->type) != KEY_ECDSA ||          if (lenp != NULL)
             key->ecdsa == NULL) {                  *lenp = 0;
                 error("%s: no ECDSA key", __func__);          if (sigp != NULL)
                 return -1;                  *sigp = NULL;
         }  
   
         hash_alg = key_ec_nid_to_hash_alg(key->ecdsa_nid);          if (key == NULL || key->ecdsa == NULL ||
         if ((dlen = ssh_digest_bytes(hash_alg)) == 0) {              sshkey_type_plain(key->type) != KEY_ECDSA)
                 error("%s: bad hash algorithm %d", __func__, hash_alg);                  return SSH_ERR_INVALID_ARGUMENT;
                 return -1;  
         }  
         if (ssh_digest_memory(hash_alg, data, datalen,  
             digest, sizeof(digest)) != 0) {  
                 error("%s: digest_memory failed", __func__);  
                 return -1;  
         }  
   
         sig = ECDSA_do_sign(digest, dlen, key->ecdsa);          if ((hash_alg = sshkey_ec_nid_to_hash_alg(key->ecdsa_nid)) == -1 ||
         explicit_bzero(digest, sizeof(digest));              (dlen = ssh_digest_bytes(hash_alg)) == 0)
                   return SSH_ERR_INTERNAL_ERROR;
           if ((ret = ssh_digest_memory(hash_alg, data, datalen,
               digest, sizeof(digest))) != 0)
                   goto out;
   
         if (sig == NULL) {          if ((sig = ECDSA_do_sign(digest, dlen, key->ecdsa)) == NULL) {
                 error("%s: sign failed", __func__);                  ret = SSH_ERR_LIBCRYPTO_ERROR;
                 return -1;                  goto out;
         }          }
   
         buffer_init(&bb);          if ((bb = sshbuf_new()) == NULL || (b = sshbuf_new()) == NULL) {
         buffer_put_bignum2(&bb, sig->r);                  ret = SSH_ERR_ALLOC_FAIL;
         buffer_put_bignum2(&bb, sig->s);                  goto out;
         ECDSA_SIG_free(sig);          }
           if ((ret = sshbuf_put_bignum2(bb, sig->r)) != 0 ||
         buffer_init(&b);              (ret = sshbuf_put_bignum2(bb, sig->s)) != 0)
         buffer_put_cstring(&b, key_ssh_name_plain(key));                  goto out;
         buffer_put_string(&b, buffer_ptr(&bb), buffer_len(&bb));          if ((ret = sshbuf_put_cstring(b, sshkey_ssh_name_plain(key))) != 0 ||
         buffer_free(&bb);              (ret = sshbuf_put_stringb(b, bb)) != 0)
         len = buffer_len(&b);                  goto out;
         if (lenp != NULL)          len = sshbuf_len(b);
                 *lenp = len;  
         if (sigp != NULL) {          if (sigp != NULL) {
                 *sigp = xmalloc(len);                  if ((*sigp = malloc(len)) == NULL) {
                 memcpy(*sigp, buffer_ptr(&b), len);                          ret = SSH_ERR_ALLOC_FAIL;
                           goto out;
                   }
                   memcpy(*sigp, sshbuf_ptr(b), len);
         }          }
         buffer_free(&b);          if (lenp != NULL)
                   *lenp = len;
         return 0;          ret = 0;
    out:
           explicit_bzero(digest, sizeof(digest));
           if (b != NULL)
                   sshbuf_free(b);
           if (bb != NULL)
                   sshbuf_free(bb);
           if (sig != NULL)
                   ECDSA_SIG_free(sig);
           return ret;
 }  }
   
   /* ARGSUSED */
 int  int
 ssh_ecdsa_verify(const Key *key, const u_char *signature, u_int signaturelen,  ssh_ecdsa_verify(const struct sshkey *key,
     const u_char *data, u_int datalen)      const u_char *signature, size_t signaturelen,
       const u_char *data, size_t datalen, u_int compat)
 {  {
         ECDSA_SIG *sig;          ECDSA_SIG *sig = NULL;
         int hash_alg;          int hash_alg;
         u_char digest[SSH_DIGEST_MAX_LENGTH], *sigblob;          u_char digest[SSH_DIGEST_MAX_LENGTH];
         u_int len, dlen;          size_t dlen;
         int rlen, ret;          int ret = SSH_ERR_INTERNAL_ERROR;
         Buffer b, bb;          struct sshbuf *b = NULL, *sigbuf = NULL;
         char *ktype;          char *ktype = NULL;
   
         if (key == NULL || key_type_plain(key->type) != KEY_ECDSA ||          if (key == NULL || key->ecdsa == NULL ||
             key->ecdsa == NULL) {              sshkey_type_plain(key->type) != KEY_ECDSA)
                 error("%s: no ECDSA key", __func__);                  return SSH_ERR_INVALID_ARGUMENT;
                 return -1;  
         }  
   
           if ((hash_alg = sshkey_ec_nid_to_hash_alg(key->ecdsa_nid)) == -1 ||
               (dlen = ssh_digest_bytes(hash_alg)) == 0)
                   return SSH_ERR_INTERNAL_ERROR;
   
         /* fetch signature */          /* fetch signature */
         buffer_init(&b);          if ((b = sshbuf_from(signature, signaturelen)) == NULL)
         buffer_append(&b, signature, signaturelen);                  return SSH_ERR_ALLOC_FAIL;
         ktype = buffer_get_string(&b, NULL);          if (sshbuf_get_cstring(b, &ktype, NULL) != 0 ||
         if (strcmp(key_ssh_name_plain(key), ktype) != 0) {              sshbuf_froms(b, &sigbuf) != 0) {
                 error("%s: cannot handle type %s", __func__, ktype);                  ret = SSH_ERR_INVALID_FORMAT;
                 buffer_free(&b);                  goto out;
                 free(ktype);  
                 return -1;  
         }          }
         free(ktype);          if (strcmp(sshkey_ssh_name_plain(key), ktype) != 0) {
         sigblob = buffer_get_string(&b, &len);                  ret = SSH_ERR_KEY_TYPE_MISMATCH;
         rlen = buffer_len(&b);                  goto out;
         buffer_free(&b);  
         if (rlen != 0) {  
                 error("%s: remaining bytes in signature %d", __func__, rlen);  
                 free(sigblob);  
                 return -1;  
         }          }
           if (sshbuf_len(b) != 0) {
                   ret = SSH_ERR_UNEXPECTED_TRAILING_DATA;
                   goto out;
           }
   
         /* parse signature */          /* parse signature */
         if ((sig = ECDSA_SIG_new()) == NULL)          if ((sig = ECDSA_SIG_new()) == NULL) {
                 fatal("%s: ECDSA_SIG_new failed", __func__);                  ret = SSH_ERR_ALLOC_FAIL;
                   goto out;
         buffer_init(&bb);  
         buffer_append(&bb, sigblob, len);  
         buffer_get_bignum2(&bb, sig->r);  
         buffer_get_bignum2(&bb, sig->s);  
         if (buffer_len(&bb) != 0)  
                 fatal("%s: remaining bytes in inner sigblob", __func__);  
         buffer_free(&bb);  
   
         /* clean up */  
         explicit_bzero(sigblob, len);  
         free(sigblob);  
   
         /* hash the data */  
         hash_alg = key_ec_nid_to_hash_alg(key->ecdsa_nid);  
         if ((dlen = ssh_digest_bytes(hash_alg)) == 0) {  
                 error("%s: bad hash algorithm %d", __func__, hash_alg);  
                 return -1;  
         }          }
         if (ssh_digest_memory(hash_alg, data, datalen,          if (sshbuf_get_bignum2(sigbuf, sig->r) != 0 ||
             digest, sizeof(digest)) != 0) {              sshbuf_get_bignum2(sigbuf, sig->s) != 0) {
                 error("%s: digest_memory failed", __func__);                  ret = SSH_ERR_INVALID_FORMAT;
                 return -1;                  goto out;
         }          }
           if (sshbuf_len(sigbuf) != 0) {
                   ret = SSH_ERR_UNEXPECTED_TRAILING_DATA;
                   goto out;
           }
           if ((ret = ssh_digest_memory(hash_alg, data, datalen,
               digest, sizeof(digest))) != 0)
                   goto out;
   
         ret = ECDSA_do_verify(digest, dlen, sig, key->ecdsa);          switch (ECDSA_do_verify(digest, dlen, sig, key->ecdsa)) {
         explicit_bzero(digest, sizeof(digest));          case 1:
                   ret = 0;
                   break;
           case 0:
                   ret = SSH_ERR_SIGNATURE_INVALID;
                   goto out;
           default:
                   ret = SSH_ERR_LIBCRYPTO_ERROR;
                   goto out;
           }
   
         ECDSA_SIG_free(sig);   out:
           explicit_bzero(digest, sizeof(digest));
         debug("%s: signature %s", __func__,          if (sigbuf != NULL)
             ret == 1 ? "correct" : ret == 0 ? "incorrect" : "error");                  sshbuf_free(sigbuf);
           if (b != NULL)
                   sshbuf_free(b);
           if (sig != NULL)
                   ECDSA_SIG_free(sig);
           free(ktype);
         return ret;          return ret;
 }  }

Legend:
Removed from v.1.10  
changed lines
  Added in v.1.11