gensignkey.c 3.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164
  1. #include "includes.h"
  2. #include "dbutil.h"
  3. #include "buffer.h"
  4. #include "ecdsa.h"
  5. #include "genrsa.h"
  6. #include "gendss.h"
  7. #include "signkey.h"
  8. #include "dbrandom.h"
  9. #define RSA_DEFAULT_SIZE 2048
  10. #define DSS_DEFAULT_SIZE 1024
  11. /* Returns DROPBEAR_SUCCESS or DROPBEAR_FAILURE */
  12. static int buf_writefile(buffer * buf, const char * filename) {
  13. int ret = DROPBEAR_FAILURE;
  14. int fd = -1;
  15. fd = open(filename, O_RDWR | O_CREAT | O_EXCL, S_IRUSR | S_IWUSR);
  16. if (fd < 0) {
  17. dropbear_log(LOG_ERR, "Couldn't create new file %s: %s",
  18. filename, strerror(errno));
  19. goto out;
  20. }
  21. /* write the file now */
  22. while (buf->pos != buf->len) {
  23. int len = write(fd, buf_getptr(buf, buf->len - buf->pos),
  24. buf->len - buf->pos);
  25. if (len == -1 && errno == EINTR) {
  26. continue;
  27. }
  28. if (len <= 0) {
  29. dropbear_log(LOG_ERR, "Failed writing file %s: %s",
  30. filename, strerror(errno));
  31. goto out;
  32. }
  33. buf_incrpos(buf, len);
  34. }
  35. ret = DROPBEAR_SUCCESS;
  36. out:
  37. if (fd >= 0) {
  38. if (fsync(fd) != 0) {
  39. dropbear_log(LOG_ERR, "fsync of %s failed: %s", filename, strerror(errno));
  40. }
  41. m_close(fd);
  42. }
  43. return ret;
  44. }
  45. /* returns 0 on failure */
  46. static int get_default_bits(enum signkey_type keytype)
  47. {
  48. switch (keytype) {
  49. #ifdef DROPBEAR_RSA
  50. case DROPBEAR_SIGNKEY_RSA:
  51. return RSA_DEFAULT_SIZE;
  52. #endif
  53. #ifdef DROPBEAR_DSS
  54. case DROPBEAR_SIGNKEY_DSS:
  55. return DSS_DEFAULT_SIZE;
  56. #endif
  57. #ifdef DROPBEAR_ECDSA
  58. case DROPBEAR_SIGNKEY_ECDSA_KEYGEN:
  59. return ECDSA_DEFAULT_SIZE;
  60. case DROPBEAR_SIGNKEY_ECDSA_NISTP521:
  61. return 521;
  62. case DROPBEAR_SIGNKEY_ECDSA_NISTP384:
  63. return 384;
  64. case DROPBEAR_SIGNKEY_ECDSA_NISTP256:
  65. return 256;
  66. #endif
  67. default:
  68. return 0;
  69. }
  70. }
  71. /* if skip_exist is set it will silently return if the key file exists */
  72. int signkey_generate(enum signkey_type keytype, int bits, const char* filename, int skip_exist)
  73. {
  74. sign_key * key = NULL;
  75. buffer *buf = NULL;
  76. char *fn_temp = NULL;
  77. int ret = DROPBEAR_FAILURE;
  78. if (bits == 0)
  79. {
  80. bits = get_default_bits(keytype);
  81. }
  82. /* now we can generate the key */
  83. key = new_sign_key();
  84. seedrandom();
  85. switch(keytype) {
  86. #ifdef DROPBEAR_RSA
  87. case DROPBEAR_SIGNKEY_RSA:
  88. key->rsakey = gen_rsa_priv_key(bits);
  89. break;
  90. #endif
  91. #ifdef DROPBEAR_DSS
  92. case DROPBEAR_SIGNKEY_DSS:
  93. key->dsskey = gen_dss_priv_key(bits);
  94. break;
  95. #endif
  96. #ifdef DROPBEAR_ECDSA
  97. case DROPBEAR_SIGNKEY_ECDSA_KEYGEN:
  98. case DROPBEAR_SIGNKEY_ECDSA_NISTP521:
  99. case DROPBEAR_SIGNKEY_ECDSA_NISTP384:
  100. case DROPBEAR_SIGNKEY_ECDSA_NISTP256:
  101. {
  102. ecc_key *ecckey = gen_ecdsa_priv_key(bits);
  103. keytype = ecdsa_signkey_type(ecckey);
  104. *signkey_key_ptr(key, keytype) = ecckey;
  105. }
  106. break;
  107. #endif
  108. default:
  109. dropbear_exit("Internal error");
  110. }
  111. seedrandom();
  112. buf = buf_new(MAX_PRIVKEY_SIZE);
  113. buf_put_priv_key(buf, key, keytype);
  114. sign_key_free(key);
  115. key = NULL;
  116. buf_setpos(buf, 0);
  117. fn_temp = m_malloc(strlen(filename) + 30);
  118. snprintf(fn_temp, strlen(filename)+30, "%s.tmp%d", filename, getpid());
  119. ret = buf_writefile(buf, fn_temp);
  120. if (ret == DROPBEAR_FAILURE) {
  121. goto out;
  122. }
  123. if (link(fn_temp, filename) < 0) {
  124. /* If generating keys on connection (skipexist) it's OK to get EEXIST
  125. - we probably just lost a race with another connection to generate the key */
  126. if (!(skip_exist && errno == EEXIST)) {
  127. dropbear_log(LOG_ERR, "Failed moving key file to %s: %s", filename,
  128. strerror(errno));
  129. /* XXX fallback to non-atomic copy for some filesystems? */
  130. ret = DROPBEAR_FAILURE;
  131. goto out;
  132. }
  133. }
  134. out:
  135. if (buf) {
  136. buf_burn(buf);
  137. buf_free(buf);
  138. }
  139. if (fn_temp) {
  140. unlink(fn_temp);
  141. m_free(fn_temp);
  142. }
  143. return ret;
  144. }