ssh-rsa.c revision 149749
118334Speter/* 290075Sobrien * Copyright (c) 2000, 2003 Markus Friedl <markus@openbsd.org> 3117395Skan * 418334Speter * Permission to use, copy, modify, and distribute this software for any 590075Sobrien * purpose with or without fee is hereby granted, provided that the above 618334Speter * copyright notice and this permission notice appear in all copies. 790075Sobrien * 890075Sobrien * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 990075Sobrien * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 1090075Sobrien * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 1118334Speter * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 1290075Sobrien * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 1390075Sobrien * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 1490075Sobrien * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 1590075Sobrien */ 1618334Speter#include "includes.h" 1718334SpeterRCSID("$OpenBSD: ssh-rsa.c,v 1.32 2005/06/17 02:44:33 djm Exp $"); 1890075Sobrien 1990075Sobrien#include <openssl/evp.h> 2090075Sobrien#include <openssl/err.h> 2118334Speter 2218334Speter#include "xmalloc.h" 2318334Speter#include "log.h" 2418334Speter#include "buffer.h" 2518334Speter#include "bufaux.h" 2618334Speter#include "key.h" 2718334Speter#include "compat.h" 2818334Speter#include "ssh.h" 2918334Speter 3050397Sobrienstatic int openssh_RSA_verify(int, u_char *, u_int, u_char *, u_int, RSA *); 3150397Sobrien 3218334Speter/* RSASSA-PKCS1-v1_5 (PKCS #1 v2.0 signature) with SHA1 */ 3318334Speterint 3418334Speterssh_rsa_sign(const Key *key, u_char **sigp, u_int *lenp, 3518334Speter const u_char *data, u_int datalen) 3618334Speter{ 3718334Speter const EVP_MD *evp_md; 3818334Speter EVP_MD_CTX md; 39117395Skan u_char digest[EVP_MAX_MD_SIZE], *sig; 4090075Sobrien u_int slen, dlen, len; 4150397Sobrien int ok, nid; 4290075Sobrien Buffer b; 4318334Speter 44117395Skan if (key == NULL || key->type != KEY_RSA || key->rsa == NULL) { 4590075Sobrien error("ssh_rsa_sign: no RSA key"); 4690075Sobrien return -1; 4790075Sobrien } 4890075Sobrien nid = (datafellows & SSH_BUG_RSASIGMD5) ? NID_md5 : NID_sha1; 4990075Sobrien if ((evp_md = EVP_get_digestbynid(nid)) == NULL) { 5018334Speter error("ssh_rsa_sign: EVP_get_digestbynid %d failed", nid); 5118334Speter return -1; 5290075Sobrien } 5390075Sobrien EVP_DigestInit(&md, evp_md); 5418334Speter EVP_DigestUpdate(&md, data, datalen); 5518334Speter EVP_DigestFinal(&md, digest, &dlen); 5650397Sobrien 5750397Sobrien slen = RSA_size(key->rsa); 5850397Sobrien sig = xmalloc(slen); 5918334Speter 6018334Speter ok = RSA_sign(nid, digest, dlen, sig, &len, key->rsa); 6190075Sobrien memset(digest, 'd', sizeof(digest)); 6218334Speter 6318334Speter if (ok != 1) { 6418334Speter int ecode = ERR_get_error(); 6590075Sobrien error("ssh_rsa_sign: RSA_sign failed: %s", 6690075Sobrien ERR_error_string(ecode, NULL)); 6718334Speter xfree(sig); 6890075Sobrien return -1; 69117395Skan } 7090075Sobrien if (len < slen) { 7190075Sobrien u_int diff = slen - len; 7290075Sobrien debug("slen %u > len %u", slen, len); 7390075Sobrien memmove(sig + diff, sig, len); 7490075Sobrien memset(sig, 0, diff); 75117395Skan } else if (len > slen) { 7690075Sobrien error("ssh_rsa_sign: slen %u slen2 %u", slen, len); 7790075Sobrien xfree(sig); 7890075Sobrien return -1; 7990075Sobrien } 8090075Sobrien /* encode signature */ 8190075Sobrien buffer_init(&b); 8290075Sobrien buffer_put_cstring(&b, "ssh-rsa"); 8390075Sobrien buffer_put_string(&b, sig, slen); 8490075Sobrien len = buffer_len(&b); 85117395Skan if (lenp != NULL) 86117395Skan *lenp = len; 87117395Skan if (sigp != NULL) { 88117395Skan *sigp = xmalloc(len); 8990075Sobrien memcpy(*sigp, buffer_ptr(&b), len); 9090075Sobrien } 91117395Skan buffer_free(&b); 92117395Skan memset(sig, 's', slen); 9390075Sobrien xfree(sig); 9490075Sobrien 9590075Sobrien return 0; 9690075Sobrien} 9790075Sobrien 9890075Sobrienint 9990075Sobrienssh_rsa_verify(const Key *key, const u_char *signature, u_int signaturelen, 10090075Sobrien const u_char *data, u_int datalen) 10190075Sobrien{ 10290075Sobrien Buffer b; 10390075Sobrien const EVP_MD *evp_md; 10490075Sobrien EVP_MD_CTX md; 10518334Speter char *ktype; 10618334Speter u_char digest[EVP_MAX_MD_SIZE], *sigblob; 10718334Speter u_int len, dlen, modlen; 10818334Speter int rlen, ret, nid; 10918334Speter 11018334Speter if (key == NULL || key->type != KEY_RSA || key->rsa == NULL) { 11118334Speter error("ssh_rsa_verify: no RSA key"); 11218334Speter return -1; 11318334Speter } 11418334Speter if (BN_num_bits(key->rsa->n) < SSH_RSA_MINIMUM_MODULUS_SIZE) { 11518334Speter error("ssh_rsa_verify: RSA modulus too small: %d < minimum %d bits", 11618334Speter BN_num_bits(key->rsa->n), SSH_RSA_MINIMUM_MODULUS_SIZE); 11718334Speter return -1; 11818334Speter } 11918334Speter buffer_init(&b); 12018334Speter buffer_append(&b, signature, signaturelen); 12118334Speter ktype = buffer_get_string(&b, NULL); 12218334Speter if (strcmp("ssh-rsa", ktype) != 0) { 12318334Speter error("ssh_rsa_verify: cannot handle type %s", ktype); 12418334Speter buffer_free(&b); 12518334Speter xfree(ktype); 12618334Speter return -1; 12790075Sobrien } 12890075Sobrien xfree(ktype); 12990075Sobrien sigblob = buffer_get_string(&b, &len); 13090075Sobrien rlen = buffer_len(&b); 13190075Sobrien buffer_free(&b); 13290075Sobrien if (rlen != 0) { 13318334Speter error("ssh_rsa_verify: remaining bytes in signature %d", rlen); 13490075Sobrien xfree(sigblob); 13518334Speter return -1; 13690075Sobrien } 13790075Sobrien /* RSA_verify expects a signature of RSA_size */ 13890075Sobrien modlen = RSA_size(key->rsa); 139117395Skan if (len > modlen) { 140117395Skan error("ssh_rsa_verify: len %u > modlen %u", len, modlen); 141117395Skan xfree(sigblob); 14290075Sobrien return -1; 14390075Sobrien } else if (len < modlen) { 14490075Sobrien u_int diff = modlen - len; 14518334Speter debug("ssh_rsa_verify: add padding: modlen %u > len %u", 146117395Skan modlen, len); 147117395Skan sigblob = xrealloc(sigblob, modlen); 148117395Skan memmove(sigblob + diff, sigblob, len); 149117395Skan memset(sigblob, 0, diff); 150117395Skan len = modlen; 15190075Sobrien } 15290075Sobrien nid = (datafellows & SSH_BUG_RSASIGMD5) ? NID_md5 : NID_sha1; 15390075Sobrien if ((evp_md = EVP_get_digestbynid(nid)) == NULL) { 15490075Sobrien error("ssh_rsa_verify: EVP_get_digestbynid %d failed", nid); 15590075Sobrien xfree(sigblob); 15690075Sobrien return -1; 15790075Sobrien } 15890075Sobrien EVP_DigestInit(&md, evp_md); 15990075Sobrien EVP_DigestUpdate(&md, data, datalen); 16090075Sobrien EVP_DigestFinal(&md, digest, &dlen); 16196263Sobrien 162117395Skan ret = openssh_RSA_verify(nid, digest, dlen, sigblob, len, key->rsa); 16390075Sobrien memset(digest, 'd', sizeof(digest)); 16490075Sobrien memset(sigblob, 's', len); 16550397Sobrien xfree(sigblob); 16690075Sobrien debug("ssh_rsa_verify: signature %scorrect", (ret==0) ? "in" : ""); 16750397Sobrien return ret; 16850397Sobrien} 16950397Sobrien 17090075Sobrien/* 17190075Sobrien * See: 17250397Sobrien * http://www.rsasecurity.com/rsalabs/pkcs/pkcs-1/ 17350397Sobrien * ftp://ftp.rsasecurity.com/pub/pkcs/pkcs-1/pkcs-1v2-1.asn 17490075Sobrien */ 17590075Sobrien/* 176117395Skan * id-sha1 OBJECT IDENTIFIER ::= { iso(1) identified-organization(3) 177102780Skan * oiw(14) secsig(3) algorithms(2) 26 } 17896263Sobrien */ 17918334Speterstatic const u_char id_sha1[] = { 18050397Sobrien 0x30, 0x21, /* type Sequence, length 0x21 (33) */ 18150397Sobrien 0x30, 0x09, /* type Sequence, length 0x09 */ 18250397Sobrien 0x06, 0x05, /* type OID, length 0x05 */ 18350397Sobrien 0x2b, 0x0e, 0x03, 0x02, 0x1a, /* id-sha1 OID */ 18490075Sobrien 0x05, 0x00, /* NULL */ 18590075Sobrien 0x04, 0x14 /* Octet string, length 0x14 (20), followed by sha1 hash */ 18650397Sobrien}; 18790075Sobrien/* 18890075Sobrien * id-md5 OBJECT IDENTIFIER ::= { iso(1) member-body(2) us(840) 18990075Sobrien * rsadsi(113549) digestAlgorithm(2) 5 } 190117395Skan */ 191117395Skanstatic const u_char id_md5[] = { 192117395Skan 0x30, 0x20, /* type Sequence, length 0x20 (32) */ 19318334Speter 0x30, 0x0c, /* type Sequence, length 0x09 */ 19450397Sobrien 0x06, 0x08, /* type OID, length 0x05 */ 19518334Speter 0x2a, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x02, 0x05, /* id-md5 */ 19650397Sobrien 0x05, 0x00, /* NULL */ 19718334Speter 0x04, 0x10 /* Octet string, length 0x10 (16), followed by md5 hash */ 198117395Skan}; 19990075Sobrien 20018334Speterstatic int 20118334Speteropenssh_RSA_verify(int type, u_char *hash, u_int hashlen, 20218334Speter u_char *sigbuf, u_int siglen, RSA *rsa) 20390075Sobrien{ 20418334Speter u_int ret, rsasize, oidlen = 0, hlen = 0; 20518334Speter int len; 20690075Sobrien const u_char *oid = NULL; 20718334Speter u_char *decrypted = NULL; 20890075Sobrien 20990075Sobrien ret = 0; 21090075Sobrien switch (type) { 21190075Sobrien case NID_sha1: 21290075Sobrien oid = id_sha1; 21390075Sobrien oidlen = sizeof(id_sha1); 21490075Sobrien hlen = 20; 21590075Sobrien break; 21690075Sobrien case NID_md5: 21790075Sobrien oid = id_md5; 21890075Sobrien oidlen = sizeof(id_md5); 21918334Speter hlen = 16; 22018334Speter break; 22118334Speter default: 22218334Speter goto done; 22318334Speter break; 22418334Speter } 22518334Speter if (hashlen != hlen) { 22618334Speter error("bad hashlen"); 22718334Speter goto done; 22818334Speter } 22918334Speter rsasize = RSA_size(rsa); 23018334Speter if (siglen == 0 || siglen > rsasize) { 231117395Skan error("bad siglen"); 23290075Sobrien goto done; 23390075Sobrien } 23490075Sobrien decrypted = xmalloc(rsasize); 23550397Sobrien if ((len = RSA_public_decrypt(siglen, sigbuf, decrypted, rsa, 23690075Sobrien RSA_PKCS1_PADDING)) < 0) { 23718334Speter error("RSA_public_decrypt failed: %s", 23818334Speter ERR_error_string(ERR_get_error(), NULL)); 23918334Speter goto done; 24018334Speter } 24118334Speter if (len < 0 || (u_int)len != hlen + oidlen) { 24218334Speter error("bad decrypted len: %d != %d + %d", len, hlen, oidlen); 24318334Speter goto done; 24418334Speter } 24518334Speter if (memcmp(decrypted, oid, oidlen) != 0) { 24618334Speter error("oid mismatch"); 247117395Skan goto done; 24850397Sobrien } 24918334Speter if (memcmp(decrypted + oidlen, hash, hlen) != 0) { 25018334Speter error("hash mismatch"); 25150397Sobrien goto done; 25218334Speter } 25350397Sobrien ret = 1; 25418334Speterdone: 25518334Speter if (decrypted) 25650397Sobrien xfree(decrypted); 25750397Sobrien return ret; 25818334Speter} 25918334Speter