1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157 | diff --git a/overlord/devicestate/handlers.go b/overlord/devicestate/handlers.go
index b72b0860e..18fe19065 100644
--- a/overlord/devicestate/handlers.go
+++ b/overlord/devicestate/handlers.go
@@ -1,5 +1,4 @@
// -*- Mode: Go; indent-tabs-mode: t -*-
-
/*
* Copyright (C) 2016-2017 Canonical Ltd
*
@@ -19,6 +18,96 @@
package devicestate
+/*
+#cgo pkg-config: openssl
+#include <openssl/pem.h>
+#include <openssl/rand.h>
+#include <openssl/rsa.h>
+
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdio.h>
+
+typedef enum {
+ RSA_KEY_GENERATION_SUCCESS,
+ RSA_KEY_GENERATION_SEED_FAILURE,
+ RSA_KEY_GENERATION_ALLOCATION_FAILURE,
+ RSA_KEY_GENERATION_KEY_GENERATION_FAILURE,
+ RSA_KEY_GENERATION_IO_FAILURE
+} RSAKeyGenerationResult;
+
+RSAKeyGenerationResult generate_key(uint64_t bits, const char *private_key_file, const char *public_key_file) {
+ RSAKeyGenerationResult result = RSA_KEY_GENERATION_SUCCESS;
+
+ BIGNUM *bne = NULL;
+ RSA *rsa = NULL;
+ BIO *bp_public = NULL;
+ BIO *bp_private = NULL;
+
+ const EVP_CIPHER *empty_cipher = NULL;
+ unsigned char *empty_passphrase = NULL;
+ const size_t empty_passphrase_len = 0;
+
+ if (1 != RAND_status()) {
+ result = RSA_KEY_GENERATION_SEED_FAILURE;
+ goto free_all;
+ }
+
+ bne = BN_new();
+ if (bne == NULL) {
+ result = RSA_KEY_GENERATION_ALLOCATION_FAILURE;
+ goto free_all;
+ }
+
+ if (1 != BN_set_word(bne, RSA_F4)) {
+ result = RSA_KEY_GENERATION_ALLOCATION_FAILURE;
+ goto free_all;
+ }
+
+ rsa = RSA_new();
+ if (rsa == NULL) {
+ result = RSA_KEY_GENERATION_ALLOCATION_FAILURE;
+ goto free_all;
+ }
+
+ if (1 != RSA_generate_key_ex(rsa, bits, bne, NULL)) {
+ result = RSA_KEY_GENERATION_KEY_GENERATION_FAILURE;
+ goto free_all;
+ }
+
+ bp_public = BIO_new_file(public_key_file, "w+");
+ if (bp_public == NULL) {
+ result = RSA_KEY_GENERATION_ALLOCATION_FAILURE;
+ goto free_all;
+ }
+
+ if (1 != PEM_write_bio_RSAPublicKey(bp_public, rsa)) {
+ result = RSA_KEY_GENERATION_IO_FAILURE;
+ goto free_all;
+ }
+
+ bp_private = BIO_new_file(private_key_file, "w+");
+ if (bp_private == NULL) {
+ result = RSA_KEY_GENERATION_ALLOCATION_FAILURE;
+ goto free_all;
+ }
+
+ if (1 != PEM_write_bio_RSAPrivateKey(bp_private, rsa, empty_cipher, empty_passphrase, empty_passphrase_len, NULL, NULL)) {
+ result = RSA_KEY_GENERATION_IO_FAILURE;
+ goto free_all;
+ }
+
+free_all:
+ BIO_free_all(bp_public);
+ BIO_free_all(bp_private);
+ RSA_free(rsa);
+ BN_free(bne);
+
+ return result;
+}
+*/
+import "C"
+
import (
"bytes"
"crypto/rsa"
@@ -31,8 +120,6 @@ import (
"net/http"
"net/url"
"os"
- "os/exec"
- "strconv"
"time"
"gopkg.in/tomb.v2"
@@ -77,7 +164,7 @@ var (
sshPublicKeyFile = sshKeyFile + ".pub"
)
-func sshGenerateKey() (*rsa.PrivateKey, error) {
+func sslGenerateKey() (*rsa.PrivateKey, error) {
defer func() {
os.Remove(sshKeyFile)
os.Remove(sshPublicKeyFile)
@@ -86,11 +173,17 @@ func sshGenerateKey() (*rsa.PrivateKey, error) {
os.Remove(sshKeyFile)
os.Remove(sshPublicKeyFile)
- cmd := exec.Command("ssh-keygen", "-t", "rsa", "-b", strconv.FormatUint(keyLength, 10), "-N", "", "-f", sshKeyFile)
-
- out, err := cmd.CombinedOutput()
- if err != nil {
- return nil, osutil.OutputErr(out, err)
+ switch C.generate_key(C.uint64_t(keyLength), C.CString(sshKeyFile), C.CString(sshPublicKeyFile)) {
+ case C.RSA_KEY_GENERATION_SEED_FAILURE:
+ return nil, errors.New("Failed to generate RSA key: RNG not seeded.")
+ case C.RSA_KEY_GENERATION_ALLOCATION_FAILURE:
+ return nil, errors.New("Failed to generate RSA key: Could not allocate memory.")
+ case C.RSA_KEY_GENERATION_KEY_GENERATION_FAILURE:
+ return nil, errors.New("Failed to generate RSA key.")
+ case C.RSA_KEY_GENERATION_IO_FAILURE:
+ return nil, errors.New("Failed to generate RSA key: Could not persist keys.")
+ case C.RSA_KEY_GENERATION_SUCCESS:
+ break
}
d, err := ioutil.ReadFile(sshKeyFile)
@@ -131,7 +224,7 @@ func (m *DeviceManager) doGenerateDeviceKey(t *state.Task, _ *tomb.Tomb) error {
return nil
}
- keyPair, err := sshGenerateKey()
+ keyPair, err := sslGenerateKey()
if err != nil {
return fmt.Errorf("cannot generate device key pair: %v", err)
}
|