ssh-xmss.c 4.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187
  1. /* $OpenBSD: ssh-xmss.c,v 1.2 2020/02/26 13:40:09 jsg Exp $*/
  2. /*
  3. * Copyright (c) 2017 Stefan-Lukas Gazdag.
  4. * Copyright (c) 2017 Markus Friedl.
  5. *
  6. * Permission to use, copy, modify, and distribute this software for any
  7. * purpose with or without fee is hereby granted, provided that the above
  8. * copyright notice and this permission notice appear in all copies.
  9. *
  10. * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
  11. * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
  12. * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
  13. * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
  14. * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
  15. * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
  16. * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  17. */
  18. #include "includes.h"
  19. #ifdef WITH_XMSS
  20. #define SSHKEY_INTERNAL
  21. #include <sys/types.h>
  22. #include <limits.h>
  23. #include <string.h>
  24. #include <stdarg.h>
  25. #include <unistd.h>
  26. #include "log.h"
  27. #include "sshbuf.h"
  28. #include "sshkey.h"
  29. #include "sshkey-xmss.h"
  30. #include "ssherr.h"
  31. #include "ssh.h"
  32. #include "xmss_fast.h"
  33. int
  34. ssh_xmss_sign(const struct sshkey *key, u_char **sigp, size_t *lenp,
  35. const u_char *data, size_t datalen, u_int compat)
  36. {
  37. u_char *sig = NULL;
  38. size_t slen = 0, len = 0, required_siglen;
  39. unsigned long long smlen;
  40. int r, ret;
  41. struct sshbuf *b = NULL;
  42. if (lenp != NULL)
  43. *lenp = 0;
  44. if (sigp != NULL)
  45. *sigp = NULL;
  46. if (key == NULL ||
  47. sshkey_type_plain(key->type) != KEY_XMSS ||
  48. key->xmss_sk == NULL ||
  49. sshkey_xmss_params(key) == NULL)
  50. return SSH_ERR_INVALID_ARGUMENT;
  51. if ((r = sshkey_xmss_siglen(key, &required_siglen)) != 0)
  52. return r;
  53. if (datalen >= INT_MAX - required_siglen)
  54. return SSH_ERR_INVALID_ARGUMENT;
  55. smlen = slen = datalen + required_siglen;
  56. if ((sig = malloc(slen)) == NULL)
  57. return SSH_ERR_ALLOC_FAIL;
  58. if ((r = sshkey_xmss_get_state(key, error)) != 0)
  59. goto out;
  60. if ((ret = xmss_sign(key->xmss_sk, sshkey_xmss_bds_state(key), sig, &smlen,
  61. data, datalen, sshkey_xmss_params(key))) != 0 || smlen <= datalen) {
  62. r = SSH_ERR_INVALID_ARGUMENT; /* XXX better error? */
  63. goto out;
  64. }
  65. /* encode signature */
  66. if ((b = sshbuf_new()) == NULL) {
  67. r = SSH_ERR_ALLOC_FAIL;
  68. goto out;
  69. }
  70. if ((r = sshbuf_put_cstring(b, "ssh-xmss@openssh.com")) != 0 ||
  71. (r = sshbuf_put_string(b, sig, smlen - datalen)) != 0)
  72. goto out;
  73. len = sshbuf_len(b);
  74. if (sigp != NULL) {
  75. if ((*sigp = malloc(len)) == NULL) {
  76. r = SSH_ERR_ALLOC_FAIL;
  77. goto out;
  78. }
  79. memcpy(*sigp, sshbuf_ptr(b), len);
  80. }
  81. if (lenp != NULL)
  82. *lenp = len;
  83. /* success */
  84. r = 0;
  85. out:
  86. if ((ret = sshkey_xmss_update_state(key, error)) != 0) {
  87. /* discard signature since we cannot update the state */
  88. if (r == 0 && sigp != NULL && *sigp != NULL) {
  89. explicit_bzero(*sigp, len);
  90. free(*sigp);
  91. }
  92. if (sigp != NULL)
  93. *sigp = NULL;
  94. if (lenp != NULL)
  95. *lenp = 0;
  96. r = ret;
  97. }
  98. sshbuf_free(b);
  99. if (sig != NULL)
  100. freezero(sig, slen);
  101. return r;
  102. }
  103. int
  104. ssh_xmss_verify(const struct sshkey *key,
  105. const u_char *signature, size_t signaturelen,
  106. const u_char *data, size_t datalen, u_int compat)
  107. {
  108. struct sshbuf *b = NULL;
  109. char *ktype = NULL;
  110. const u_char *sigblob;
  111. u_char *sm = NULL, *m = NULL;
  112. size_t len, required_siglen;
  113. unsigned long long smlen = 0, mlen = 0;
  114. int r, ret;
  115. if (key == NULL ||
  116. sshkey_type_plain(key->type) != KEY_XMSS ||
  117. key->xmss_pk == NULL ||
  118. sshkey_xmss_params(key) == NULL ||
  119. signature == NULL || signaturelen == 0)
  120. return SSH_ERR_INVALID_ARGUMENT;
  121. if ((r = sshkey_xmss_siglen(key, &required_siglen)) != 0)
  122. return r;
  123. if (datalen >= INT_MAX - required_siglen)
  124. return SSH_ERR_INVALID_ARGUMENT;
  125. if ((b = sshbuf_from(signature, signaturelen)) == NULL)
  126. return SSH_ERR_ALLOC_FAIL;
  127. if ((r = sshbuf_get_cstring(b, &ktype, NULL)) != 0 ||
  128. (r = sshbuf_get_string_direct(b, &sigblob, &len)) != 0)
  129. goto out;
  130. if (strcmp("ssh-xmss@openssh.com", ktype) != 0) {
  131. r = SSH_ERR_KEY_TYPE_MISMATCH;
  132. goto out;
  133. }
  134. if (sshbuf_len(b) != 0) {
  135. r = SSH_ERR_UNEXPECTED_TRAILING_DATA;
  136. goto out;
  137. }
  138. if (len != required_siglen) {
  139. r = SSH_ERR_INVALID_FORMAT;
  140. goto out;
  141. }
  142. if (datalen >= SIZE_MAX - len) {
  143. r = SSH_ERR_INVALID_ARGUMENT;
  144. goto out;
  145. }
  146. smlen = len + datalen;
  147. mlen = smlen;
  148. if ((sm = malloc(smlen)) == NULL || (m = malloc(mlen)) == NULL) {
  149. r = SSH_ERR_ALLOC_FAIL;
  150. goto out;
  151. }
  152. memcpy(sm, sigblob, len);
  153. memcpy(sm+len, data, datalen);
  154. if ((ret = xmss_sign_open(m, &mlen, sm, smlen,
  155. key->xmss_pk, sshkey_xmss_params(key))) != 0) {
  156. debug2("%s: crypto_sign_xmss_open failed: %d",
  157. __func__, ret);
  158. }
  159. if (ret != 0 || mlen != datalen) {
  160. r = SSH_ERR_SIGNATURE_INVALID;
  161. goto out;
  162. }
  163. /* XXX compare 'm' and 'data' ? */
  164. /* success */
  165. r = 0;
  166. out:
  167. if (sm != NULL)
  168. freezero(sm, smlen);
  169. if (m != NULL)
  170. freezero(m, smlen);
  171. sshbuf_free(b);
  172. free(ktype);
  173. return r;
  174. }
  175. #endif /* WITH_XMSS */