Add a basic signing tool.
This is mostly to make it easier for me to generate test Ed25519
certificates.
Change-Id: I45e42f556d949d62eb6cdf684194958fa9f909bf
Reviewed-on: https://boringssl-review.googlesource.com/14504
Reviewed-by: Adam Langley <agl@google.com>
diff --git a/tool/CMakeLists.txt b/tool/CMakeLists.txt
index f0af283..244f7df 100644
--- a/tool/CMakeLists.txt
+++ b/tool/CMakeLists.txt
@@ -8,11 +8,13 @@
client.cc
const.cc
digest.cc
+ file.cc
generate_ed25519.cc
genrsa.cc
pkcs12.cc
rand.cc
server.cc
+ sign.cc
speed.cc
tool.cc
transport_common.cc
diff --git a/tool/file.cc b/tool/file.cc
new file mode 100644
index 0000000..9b5ff1b
--- /dev/null
+++ b/tool/file.cc
@@ -0,0 +1,50 @@
+/* Copyright (c) 2017, Google Inc.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+ * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
+ * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */
+
+#include <stdio.h>
+
+#include <algorithm>
+#include <vector>
+
+#include "internal.h"
+
+
+bool ReadAll(std::vector<uint8_t> *out, FILE *file) {
+ out->clear();
+
+ constexpr size_t kMaxSize = 1024 * 1024;
+ size_t len = 0;
+ out->resize(128);
+
+ for (;;) {
+ len += fread(out->data() + len, 1, out->size() - len, file);
+
+ if (feof(file)) {
+ out->resize(len);
+ return true;
+ }
+ if (ferror(file)) {
+ return false;
+ }
+
+ if (len == out->size()) {
+ if (out->size() == kMaxSize) {
+ fprintf(stderr, "Input too large.\n");
+ return false;
+ }
+ size_t cap = std::min(out->size() * 2, kMaxSize);
+ out->resize(cap);
+ }
+ }
+}
diff --git a/tool/internal.h b/tool/internal.h
index fd66e00..80c9dc9 100644
--- a/tool/internal.h
+++ b/tool/internal.h
@@ -65,6 +65,8 @@
unsigned default_value,
const std::map<std::string, std::string> &args);
+bool ReadAll(std::vector<uint8_t> *out, FILE *in);
+
bool Ciphers(const std::vector<std::string> &args);
bool Client(const std::vector<std::string> &args);
bool DoPKCS12(const std::vector<std::string> &args);
@@ -78,6 +80,7 @@
bool SHA384Sum(const std::vector<std::string> &args);
bool SHA512Sum(const std::vector<std::string> &args);
bool Server(const std::vector<std::string> &args);
+bool Sign(const std::vector<std::string> &args);
bool Speed(const std::vector<std::string> &args);
// These values are DER encoded, RSA private keys.
diff --git a/tool/server.cc b/tool/server.cc
index 1a97dff..13c7825 100644
--- a/tool/server.cc
+++ b/tool/server.cc
@@ -14,6 +14,8 @@
#include <openssl/base.h>
+#include <memory>
+
#include <openssl/err.h>
#include <openssl/rand.h>
#include <openssl/ssl.h>
@@ -61,44 +63,28 @@
},
};
+struct FileCloser {
+ void operator()(FILE *file) {
+ fclose(file);
+ }
+};
+
+using ScopedFILE = std::unique_ptr<FILE, FileCloser>;
+
static bool LoadOCSPResponse(SSL_CTX *ctx, const char *filename) {
- void *data = NULL;
- bool ret = false;
- size_t bytes_read;
- long length;
-
- FILE *f = fopen(filename, "rb");
-
- if (f == NULL ||
- fseek(f, 0, SEEK_END) != 0) {
- goto out;
+ ScopedFILE f(fopen(filename, "rb"));
+ std::vector<uint8_t> data;
+ if (f == nullptr ||
+ !ReadAll(&data, f.get())) {
+ fprintf(stderr, "Error reading %s.\n", filename);
+ return false;
}
- length = ftell(f);
- if (length < 0) {
- goto out;
+ if (!SSL_CTX_set_ocsp_response(ctx, data.data(), data.size())) {
+ return false;
}
- data = malloc(length);
- if (data == NULL) {
- goto out;
- }
- rewind(f);
-
- bytes_read = fread(data, 1, length, f);
- if (ferror(f) != 0 ||
- bytes_read != (size_t)length ||
- !SSL_CTX_set_ocsp_response(ctx, (uint8_t*)data, bytes_read)) {
- goto out;
- }
-
- ret = true;
-out:
- if (f != NULL) {
- fclose(f);
- }
- free(data);
- return ret;
+ return true;
}
static bssl::UniquePtr<EVP_PKEY> MakeKeyPairForSelfSignedCert() {
diff --git a/tool/sign.cc b/tool/sign.cc
new file mode 100644
index 0000000..74b84f1
--- /dev/null
+++ b/tool/sign.cc
@@ -0,0 +1,88 @@
+/* Copyright (c) 2017, Google Inc.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+ * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
+ * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */
+
+#include <map>
+#include <vector>
+
+#include <openssl/bio.h>
+#include <openssl/evp.h>
+#include <openssl/pem.h>
+
+#include "internal.h"
+
+
+static const struct argument kArguments[] = {
+ {"-key", kRequiredArgument, "The private key, in PEM format, to sign with"},
+ {"-digest", kOptionalArgument, "The digest algorithm to use"},
+ {"", kOptionalArgument, ""},
+};
+
+bool Sign(const std::vector<std::string> &args) {
+ std::map<std::string, std::string> args_map;
+ if (!ParseKeyValueArguments(&args_map, args, kArguments)) {
+ PrintUsage(kArguments);
+ return false;
+ }
+
+ // Load the private key.
+ bssl::UniquePtr<BIO> bio(BIO_new(BIO_s_file()));
+ if (!bio || !BIO_read_filename(bio.get(), args_map["-key"].c_str())) {
+ return false;
+ }
+ bssl::UniquePtr<EVP_PKEY> key(
+ PEM_read_bio_PrivateKey(bio.get(), nullptr, nullptr, nullptr));
+ if (!key) {
+ return false;
+ }
+
+ // Setup the signing operation.
+ bssl::UniquePtr<EVP_PKEY_CTX> ctx(EVP_PKEY_CTX_new(key.get(), nullptr));
+ if (!ctx ||
+ !EVP_PKEY_sign_init(ctx.get())) {
+ return false;
+ }
+
+ if (args_map.count("-digest")) {
+ const EVP_MD *md = EVP_get_digestbyname(args_map["-digest"].c_str());
+ if (md == nullptr) {
+ fprintf(stderr, "Unknown digest algorithm: %s\n",
+ args_map["-digest"].c_str());
+ return false;
+ }
+
+ if (!EVP_PKEY_CTX_set_signature_md(ctx.get(), md)) {
+ return false;
+ }
+ }
+
+ std::vector<uint8_t> data;
+ if (!ReadAll(&data, stdin)) {
+ fprintf(stderr, "Error reading input.\n");
+ return false;
+ }
+
+ size_t sig_len = EVP_PKEY_size(key.get());
+ std::unique_ptr<uint8_t[]> sig(new uint8_t[sig_len]);
+ if (!EVP_PKEY_sign_message(ctx.get(), sig.get(), &sig_len, data.data(),
+ data.size())) {
+ return false;
+ }
+
+ if (fwrite(sig.get(), 1, sig_len, stdout) != sig_len) {
+ fprintf(stderr, "Error writing signature.\n");
+ return false;
+ }
+
+ return true;
+}
diff --git a/tool/tool.cc b/tool/tool.cc
index 34851b4..d698561 100644
--- a/tool/tool.cc
+++ b/tool/tool.cc
@@ -52,6 +52,7 @@
{ "sha256sum", SHA256Sum },
{ "sha384sum", SHA384Sum },
{ "sha512sum", SHA512Sum },
+ { "sign", Sign },
{ "speed", Speed },
{ "", nullptr },
};
@@ -122,5 +123,10 @@
args.push_back(argv[i]);
}
- return !tool(args);
+ if (!tool(args)) {
+ ERR_print_errors_fp(stderr);
+ return 1;
+ }
+
+ return 0;
}