Skip to content

Instantly share code, notes, and snippets.

@trueroad
Last active November 29, 2020 10:17
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save trueroad/40072532a258b3519c8f6beabe829b0c to your computer and use it in GitHub Desktop.
Save trueroad/40072532a258b3519c8f6beabe829b0c to your computer and use it in GitHub Desktop.
Time stamp (RFC 3161) tools
-- From RFC 2630 / 3369 / 3852 / 5652 --
CryptographicMessageSyntax2004
{ iso(1) member-body(2) us(840) rsadsi(113549)
pkcs(1) pkcs-9(9) smime(16) modules(0) cms-2004(24) }
DEFINITIONS IMPLICIT TAGS ::=
BEGIN
-- ... --
-- Cryptographic Message Syntax
ContentInfo ::= SEQUENCE {
contentType ContentType,
content [0] EXPLICIT ANY DEFINED BY contentType }
ContentType ::= OBJECT IDENTIFIER
SignedData ::= SEQUENCE {
version CMSVersion,
digestAlgorithms DigestAlgorithmIdentifiers,
encapContentInfo EncapsulatedContentInfo,
certificates [0] IMPLICIT CertificateSet OPTIONAL,
crls [1] IMPLICIT RevocationInfoChoices OPTIONAL,
signerInfos SignerInfos }
DigestAlgorithmIdentifiers ::= SET OF DigestAlgorithmIdentifier
SignerInfos ::= SET OF SignerInfo
EncapsulatedContentInfo ::= SEQUENCE {
eContentType ContentType,
eContent [0] EXPLICIT OCTET STRING OPTIONAL }
SignerInfo ::= SEQUENCE {
version CMSVersion,
sid SignerIdentifier,
digestAlgorithm DigestAlgorithmIdentifier,
signedAttrs [0] IMPLICIT SignedAttributes OPTIONAL,
signatureAlgorithm SignatureAlgorithmIdentifier,
signature SignatureValue,
unsignedAttrs [1] IMPLICIT UnsignedAttributes OPTIONAL }
SignerIdentifier ::= CHOICE {
issuerAndSerialNumber IssuerAndSerialNumber,
subjectKeyIdentifier [0] SubjectKeyIdentifier }
SignedAttributes ::= SET SIZE (1..MAX) OF Attribute
UnsignedAttributes ::= SET SIZE (1..MAX) OF Attribute
Attribute ::= SEQUENCE {
attrType OBJECT IDENTIFIER,
attrValues SET OF AttributeValue }
AttributeValue ::= ANY
SignatureValue ::= OCTET STRING
-- ... --
SubjectKeyIdentifier ::= OCTET STRING
-- ... --
DigestAlgorithmIdentifier ::= AlgorithmIdentifier
SignatureAlgorithmIdentifier ::= AlgorithmIdentifier
-- ... --
CMSVersion ::= INTEGER { v0(0), v1(1), v2(2), v3(3), v4(4), v5(5) }
-- ... --
-- From RFC 2459 / 3280 / 5280 --
-- ... --
AlgorithmIdentifier ::= SEQUENCE {
algorithm OBJECT IDENTIFIER,
parameters ANY DEFINED BY algorithm OPTIONAL }
-- contains a value of the type
-- registered for use with the
-- algorithm object identifier value
-- ... --
-- dummy --
-- RFC 5652
RevocationInfoChoices ::= SET OF ANY
CertificateSet ::= SET OF ANY
IssuerAndSerialNumber ::= SEQUENCE OF ANY
END
#if HAVE_CONFIG_H
# include "config.h"
#endif
#include <libtasn1.h>
const asn1_static_node cms_asn1_tab[] = {
{ "CryptographicMessageSyntax2004", 536875024, NULL },
{ NULL, 1610612748, NULL },
{ "iso", 1073741825, "1"},
{ "member-body", 1073741825, "2"},
{ "us", 1073741825, "840"},
{ "rsadsi", 1073741825, "113549"},
{ "pkcs", 1073741825, "1"},
{ "pkcs-9", 1073741825, "9"},
{ "smime", 1073741825, "16"},
{ "modules", 1073741825, "0"},
{ "cms-2004", 1, "24"},
{ "ContentInfo", 1610612741, NULL },
{ "contentType", 1073741826, "ContentType"},
{ "content", 541073421, NULL },
{ NULL, 1073743880, "0"},
{ "contentType", 1, NULL },
{ "ContentType", 1073741836, NULL },
{ "SignedData", 1610612741, NULL },
{ "version", 1073741826, "CMSVersion"},
{ "digestAlgorithms", 1073741826, "DigestAlgorithmIdentifiers"},
{ "encapContentInfo", 1073741826, "EncapsulatedContentInfo"},
{ "certificates", 1610637314, "CertificateSet"},
{ NULL, 4104, "0"},
{ "crls", 1610637314, "RevocationInfoChoices"},
{ NULL, 4104, "1"},
{ "signerInfos", 2, "SignerInfos"},
{ "DigestAlgorithmIdentifiers", 1610612751, NULL },
{ NULL, 2, "DigestAlgorithmIdentifier"},
{ "SignerInfos", 1610612751, NULL },
{ NULL, 2, "SignerInfo"},
{ "EncapsulatedContentInfo", 1610612741, NULL },
{ "eContentType", 1073741826, "ContentType"},
{ "eContent", 536895495, NULL },
{ NULL, 2056, "0"},
{ "SignerInfo", 1610612741, NULL },
{ "version", 1073741826, "CMSVersion"},
{ "sid", 1073741826, "SignerIdentifier"},
{ "digestAlgorithm", 1073741826, "DigestAlgorithmIdentifier"},
{ "signedAttrs", 1610637314, "SignedAttributes"},
{ NULL, 4104, "0"},
{ "signatureAlgorithm", 1073741826, "SignatureAlgorithmIdentifier"},
{ "signature", 1073741826, "SignatureValue"},
{ "unsignedAttrs", 536895490, "UnsignedAttributes"},
{ NULL, 4104, "1"},
{ "SignerIdentifier", 1610612754, NULL },
{ "issuerAndSerialNumber", 1073741826, "IssuerAndSerialNumber"},
{ "subjectKeyIdentifier", 536879106, "SubjectKeyIdentifier"},
{ NULL, 4104, "0"},
{ "SignedAttributes", 1612709903, NULL },
{ "MAX", 1074266122, "1"},
{ NULL, 2, "Attribute"},
{ "UnsignedAttributes", 1612709903, NULL },
{ "MAX", 1074266122, "1"},
{ NULL, 2, "Attribute"},
{ "Attribute", 1610612741, NULL },
{ "attrType", 1073741836, NULL },
{ "attrValues", 536870927, NULL },
{ NULL, 2, "AttributeValue"},
{ "AttributeValue", 1073741837, NULL },
{ "SignatureValue", 1073741831, NULL },
{ "SubjectKeyIdentifier", 1073741831, NULL },
{ "DigestAlgorithmIdentifier", 1073741826, "AlgorithmIdentifier"},
{ "SignatureAlgorithmIdentifier", 1073741826, "AlgorithmIdentifier"},
{ "CMSVersion", 1610874883, NULL },
{ "v0", 1073741825, "0"},
{ "v1", 1073741825, "1"},
{ "v2", 1073741825, "2"},
{ "v3", 1073741825, "3"},
{ "v4", 1073741825, "4"},
{ "v5", 1, "5"},
{ "AlgorithmIdentifier", 1610612741, NULL },
{ "algorithm", 1073741836, NULL },
{ "parameters", 541081613, NULL },
{ "algorithm", 1, NULL },
{ "RevocationInfoChoices", 1610612751, NULL },
{ NULL, 13, NULL },
{ "CertificateSet", 1610612751, NULL },
{ NULL, 13, NULL },
{ "IssuerAndSerialNumber", 536870923, NULL },
{ NULL, 13, NULL },
{ NULL, 0, NULL }
};
BIN_REQ = ts_req
OBJS_REQ = ts_req.o tr_libtasn1.o \
tr_hash_gnutls.o tr_gnutls_init.o ts_asn1_tab.o
BIN_PKCS7_REQ = pkcs7_ts_req
OBJS_PKCS7_REQ = pkcs7_ts_req.o tr_libtasn1.o \
tr_hash_gnutls.o tr_gnutls_init.o \
ts_asn1_tab.o cms_asn1_tab.o
BIN_RESP = ts_resp
OBJS_RESP = ts_resp.o tr_libtasn1.o tr_hash_gnutls.o \
ts_asn1_tab.o cms_asn1_tab.o
BIN_MERGE = merge_sign
OBJS_MERGE = merge_sign.o tr_libtasn1.o cms_asn1_tab.o
ASN1PARSER = asn1Parser
BIN = $(sort $(BIN_REQ) $(BIN_PKCS7_REQ) $(BIN_RESP) $(BIN_MERGE))
OBJS = $(sort $(OBJS_REQ) $(OBJS_PKCS7_REQ) $(OBJS_RESP) $(OBJS_MERGE))
all: $(BIN) ts_asn1_tab.c cms_asn1_tab.c
.PHONY: all clean
CXXFLAGS += -std=c++11
LDLIBS += -ltasn1 -lgnutls
DEPS = $(OBJS:.o=.d)
CPPFLAGS += -MMD -MP -MF $(@:.o=.d) -MT $@
-include $(DEPS)
$(BIN_REQ): $(OBJS_REQ)
$(LINK.cc) $^ $(LOADLIBES) $(LDLIBS) -o $@
$(BIN_PKCS7_REQ): $(OBJS_PKCS7_REQ)
$(LINK.cc) $^ $(LOADLIBES) $(LDLIBS) -o $@
$(BIN_RESP): $(OBJS_RESP)
$(LINK.cc) $^ $(LOADLIBES) $(LDLIBS) -o $@
$(BIN_MERGE): $(OBJS_MERGE)
$(LINK.cc) $^ $(LOADLIBES) $(LDLIBS) -o $@
%_asn1_tab.c: %.asn1
$(ASN1PARSER) -o $@ $^
clean:
$(RM) *~ $(OBJS) $(DEPS)
//
// Time stamp (RFC 3161) tools
// https://gist.github.com/trueroad/40072532a258b3519c8f6beabe829b0c
//
// merge_sign.cc:
// PKCS#7 signed-data merger
//
// Copyright (C) 2019 Masamichi Hosoda.
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions
// are met:
//
// * Redistributions of source code must retain the above copyright notice,
// this list of conditions and the following disclaimer.
//
// * Redistributions in binary form must reproduce the above copyright notice,
// this list of conditions and the following disclaimer in the documentation
// and/or other materials provided with the distribution.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
// ARE DISCLAIMED.
// IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
// OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
// HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
// LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
// OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
// SUCH DAMAGE.
//
#include <fstream>
#include <iostream>
#include <stdexcept>
#include <string>
#include <vector>
#include "tr_libtasn1.hh"
#include "tr_util_binary.hh"
extern "C" const asn1_static_node cms_asn1_tab[];
int main (int argc, char *argv[])
{
std::cout
<< "PKCS#7 signed-data merger"
<< std::endl
<< "Copyright (C) 2019 Masamichi Hosoda"
<< std::endl << std::endl;
if (argc != 4)
{
std::cout
<< "usage: " << argv[0]
<< " (in)MAIN.p7s (in)SUB.p7s (out)MERGED.p7s"
<< std::endl;
return 1;
}
std::string filename_main {argv[1]};
std::string filename_sub {argv[2]};
std::string filename_merged {argv[3]};
std::cout
<< "main filename: " << filename_main << std::endl
<< "sub filename: " << filename_sub << std::endl
<< "merged filename: " << filename_merged << std::endl << std::endl;
try
{
tr_libtasn1::asn1_definition d (cms_asn1_tab);
std::cout << "decoding main..." << std::endl;
auto s_ci {d.create_element
("CryptographicMessageSyntax2004.ContentInfo")};
s_ci.der_decoding (tr_util::fileload_binary (filename_main));
std::cout << "decoding main signed-data..." << std::endl;
auto sd {s_ci.read_value_binary ("content")};
auto s_sd {d.create_element
("CryptographicMessageSyntax2004.SignedData")};
s_sd.der_decoding (sd);
std::cout << "checking signature..." << std::endl;
auto signs {s_sd.number_of_elements ("signerInfos")};
if (signs > 1)
{
std::cout << "error: There are multiple signatures." << std::endl
<< "signerInfos has " << signs
<< " elements" << std::endl;
return 1;
}
else if (signs == 0)
{
std::cout << "error: There are no signatures." << std::endl
<< "signerInfos has no elements" << std::endl;
return 1;
}
std::cout << "appending new signerInfos..." << std::endl;
s_sd.write_value ("signerInfos", "NEW", 1);
std::cout << "copying signerInfos..."
<< std::endl;
s_sd.copy_node ("signerInfos.?2.version",
"signerInfos.?1.version");
s_sd.copy_node ("signerInfos.?2.sid",
"signerInfos.?1.sid");
s_sd.copy_node ("signerInfos.?2.digestAlgorithm",
"signerInfos.?1.digestAlgorithm");
{
auto nodes {s_sd.number_of_elements_optional
("signerInfos.?1.signedAttrs")};
if (nodes > 0)
{
for (int i = 1; i <= nodes; ++i)
{
s_sd.write_value ("signerInfos.?2.signedAttrs", "NEW", 1);
s_sd.copy_node ("signerInfos.?2.signedAttrs.?"
+ std::to_string (i),
"signerInfos.?1.signedAttrs.?"
+ std::to_string (i));
}
}
else
s_sd.delete_element ("signerInfos.?2.signedAttrs");
}
s_sd.copy_node ("signerInfos.?2.signatureAlgorithm",
"signerInfos.?1.signatureAlgorithm");
s_sd.copy_node ("signerInfos.?2.signature",
"signerInfos.?1.signature");
{
auto nodes {s_sd.number_of_elements_optional
("signerInfos.?1.unsignedAttrs")};
if (nodes > 0)
{
for (int i = 1; i <= nodes; ++i)
{
s_sd.write_value ("signerInfos.?2.unsignedAttrs", "NEW", 1);
s_sd.copy_node ("signerInfos.?2.unsignedAttrs.?"
+ std::to_string (i),
"signerInfos.?1.unsignedAttrs.?"
+ std::to_string (i));
}
}
}
std::cout << "adding new unsignedAttrs..." << std::endl;
s_sd.write_value ("signerInfos.?2.unsignedAttrs", "NEW", 1);
s_sd.write_value ("signerInfos.?2.unsignedAttrs.?LAST.attrType",
"1.2.840.113549.1.9.16.2.14");
s_sd.write_value ("signerInfos.?2.unsignedAttrs.?LAST.attrValues",
"NEW", 1);
s_sd.write_value ("signerInfos.?2.unsignedAttrs.?LAST.attrValues.?1",
tr_util::fileload_binary (filename_sub));
std::cout << "deleting old signerInfos..." << std::endl;
s_sd.delete_element ("signerInfos.?1");
std::cout << "creating new pkcs7 signed-data..." << std::endl;
auto s_ci_merged {d.create_element
("CryptographicMessageSyntax2004.ContentInfo")};
s_ci_merged.write_value ("contentType", "1.2.840.113549.1.7.2");
auto sd_der {s_sd.der_coding ("")};
s_ci_merged.write_value ("content", sd_der);
std::cout << "coding new pkcs7 signed-data..." << std::endl;
auto merged {s_ci_merged.der_coding ("")};
std::cout << "writing file \"" << filename_merged
<< "\"..." << std::endl;
tr_util::filesave (filename_merged, merged);
}
catch (std::runtime_error &e)
{
std::cout << e.what () << std::endl;
return 1;
}
std::cout << std::endl << "complete" << std::endl;
return 0;
}
//
// Time stamp (RFC 3161) tools
// https://gist.github.com/trueroad/40072532a258b3519c8f6beabe829b0c
//
// pkcs7_ts_req.cc:
// Time stamp request generator for PKCS#7 signed-data
//
// Copyright (C) 2019, 2020 Masamichi Hosoda.
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions
// are met:
//
// * Redistributions of source code must retain the above copyright notice,
// this list of conditions and the following disclaimer.
//
// * Redistributions in binary form must reproduce the above copyright notice,
// this list of conditions and the following disclaimer in the documentation
// and/or other materials provided with the distribution.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
// ARE DISCLAIMED.
// IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
// OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
// HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
// LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
// OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
// SUCH DAMAGE.
//
#include <fstream>
#include <iostream>
#include <stdexcept>
#include <string>
#include <vector>
#include "tr_gnutls_init.hh"
#include "tr_util_binary.hh"
#include "ts_req_gen_req.hh"
extern "C" const asn1_static_node cms_asn1_tab[];
namespace
{
std::vector<unsigned char> get_signature_value (const std::string &filename)
{
tr_libtasn1::asn1_definition d (cms_asn1_tab);
auto s_ci {d.create_element
("CryptographicMessageSyntax2004.ContentInfo")};
s_ci.der_decoding (tr_util::fileload_binary (filename));
auto sd {s_ci.read_value_binary ("content")};
auto s_sd {d.create_element ("CryptographicMessageSyntax2004.SignedData")};
s_sd.der_decoding (sd);
auto signs {s_sd.number_of_elements ("signerInfos")};
if (signs > 1)
{
throw std::runtime_error ("error: There are multiple signatures.");
}
else if (signs == 0)
{
throw std::runtime_error ("error: There are no signatures.");
}
return s_sd.read_value_binary ("signerInfos.?1.signature");
}
}
int main (int argc, char *argv[])
{
std::cout
<< "Time stamp request (RFC 3161) generator for PKCS#7 signed-data"
<< std::endl
<< "Copyright (C) 2019, 2020 Masamichi Hosoda"
<< std::endl << std::endl;
if (argc != 4)
{
std::cout
<< "usage: " << argv[0]
<< " DIGEST (in)TO-BE-SIGNED.p7s (out)TIME-STAMP-REQUEST.bin"
<< std::endl << std::endl
<< " DIGEST: sha256|sha384|sha512|sha1|ripemd160"
<< std::endl;
return 1;
}
std::string digest {argv[1]};
std::string filename_in {argv[2]};
std::string filename_out {argv[3]};
std::cout
<< "digest: " << digest << std::endl
<< "input filename: " << filename_in << std::endl
<< "output filename: " << filename_out << std::endl << std::endl;
try
{
tr_gnutls::global_init g;
auto req {gen_req (digest, get_signature_value (filename_in))};
if (req.size () == 0)
{
std::cout << "generate failed" << std::endl;
return 1;
}
std::cout << "der_coding succeeded" << std::endl
<< tr_util::binary_hex (req) << std::flush;
std::cout << std::endl
<< "writing request file \"" << filename_out
<< "\"..." << std::endl;
tr_util::filesave (filename_out, req);
}
catch (std::runtime_error &e)
{
std::cout << e.what () << std::endl;
return 1;
}
std::cout << std::endl << "complete" << std::endl;
return 0;
}
//
// Global initializer for GnuTLS
//
// tr_gnutls_init.cc:
// Implementation
//
// Copyright (C) 2019 Masamichi Hosoda.
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions
// are met:
//
// * Redistributions of source code must retain the above copyright notice,
// this list of conditions and the following disclaimer.
//
// * Redistributions in binary form must reproduce the above copyright notice,
// this list of conditions and the following disclaimer in the documentation
// and/or other materials provided with the distribution.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
// ARE DISCLAIMED.
// IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
// OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
// HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
// LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
// OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
// SUCH DAMAGE.
//
#include "tr_gnutls_init.hh"
#include <stdexcept>
#include <sstream>
#include <string>
#include <gnutls/gnutls.h>
namespace tr_gnutls
{
global_init::global_init ()
{
int ret = gnutls_global_init ();
if (ret < 0)
{
std::stringstream ss;
ss << "tr_gnutls::global_init: gnutls_global_init failed "
<< ret;
throw std::runtime_error (ss.str ().c_str ());
}
}
global_init::~global_init ()
{
gnutls_global_deinit();
}
}
//
// Global initializer for GnuTLS
//
// tr_gnutls_init.hh:
// Header file
//
// Copyright (C) 2019 Masamichi Hosoda.
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions
// are met:
//
// * Redistributions of source code must retain the above copyright notice,
// this list of conditions and the following disclaimer.
//
// * Redistributions in binary form must reproduce the above copyright notice,
// this list of conditions and the following disclaimer in the documentation
// and/or other materials provided with the distribution.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
// ARE DISCLAIMED.
// IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
// OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
// HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
// LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
// OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
// SUCH DAMAGE.
//
#ifndef INCLUDE_GUARD_TR_GNUTLS_INIT_HH
#define INCLUDE_GUARD_TR_GNUTLS_INIT_HH
namespace tr_gnutls
{
class global_init
{
public:
global_init ();
~global_init ();
global_init (const global_init &) = delete;
global_init& operator= (const global_init &) = delete;
global_init (global_init &&) = delete;
global_init& operator= (global_init &&) = delete;
};
}
#endif // INCLUDE_GUARD_TR_GNUTLS_INIT_HH
//
// Random number generator using GnuTLS
//
// tr_gnutls_rnd.hh:
// Header file / implementation
//
// Copyright (C) 2019 Masamichi Hosoda.
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions
// are met:
//
// * Redistributions of source code must retain the above copyright notice,
// this list of conditions and the following disclaimer.
//
// * Redistributions in binary form must reproduce the above copyright notice,
// this list of conditions and the following disclaimer in the documentation
// and/or other materials provided with the distribution.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
// ARE DISCLAIMED.
// IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
// OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
// HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
// LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
// OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
// SUCH DAMAGE.
//
#ifndef INCLUDE_GUARD_TR_GNUTLS_RND_HH
#define INCLUDE_GUARD_TR_GNUTLS_RND_HH
#include <stdexcept>
#include <sstream>
#include <string>
#include <vector>
#include <gnutls/crypto.h>
namespace tr_gnutls
{
inline
std::vector<unsigned char> rnd (gnutls_rnd_level_t level, size_t len)
{
std::vector<unsigned char> buff (len);
int ret = gnutls_rnd (level, buff.data (), len);
if (ret < 0)
{
std::stringstream ss;
ss << "tr_gnutls::rnd: gnutls_rnd failed: "
<< gnutls_strerror (ret);
throw std::runtime_error (ss.str ().c_str ());
}
return buff;
}
};
#endif // INCLUDE_GUARD_TR_GNUTLS_RND_HH
//
// tr_hash: C++ class library for hash calculation
// https://gist.github.com/trueroad/249bba7aaaada8eca8cab30dae8215b1
//
// tr_hash.hh:
// Header file for tr_hash
//
// Copyright (C) 2019 Masamichi Hosoda.
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions
// are met:
//
// * Redistributions of source code must retain the above copyright notice,
// this list of conditions and the following disclaimer.
//
// * Redistributions in binary form must reproduce the above copyright notice,
// this list of conditions and the following disclaimer in the documentation
// and/or other materials provided with the distribution.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
// ARE DISCLAIMED.
// IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
// OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
// HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
// LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
// OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
// SUCH DAMAGE.
//
#ifndef INCLUDE_GUARD_TR_HASH_HH
#define INCLUDE_GUARD_TR_HASH_HH
#include <memory>
#include <string>
#include <vector>
namespace tr_hash
{
class hash
{
public:
hash (const std::string & /* name */);
~hash ();
hash (const hash &) = delete;
hash& operator= (const hash &) = delete;
hash (hash &&);
hash& operator= (hash &&);
explicit operator bool ();
std::vector<unsigned char>
calc (const std::vector<unsigned char> & /* input */);
std::string oid ();
private:
class impl;
std::unique_ptr<impl> pimpl_;
};
}
#endif // INCLUDE_GUARD_TR_HASH_HH
//
// tr_hash: C++ class library for hash calculation
// https://gist.github.com/trueroad/249bba7aaaada8eca8cab30dae8215b1
//
// tr_hash_gnutls.cc:
// Implementation for tr_hash with GnuTLS
//
// Copyright (C) 2019 Masamichi Hosoda.
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions
// are met:
//
// * Redistributions of source code must retain the above copyright notice,
// this list of conditions and the following disclaimer.
//
// * Redistributions in binary form must reproduce the above copyright notice,
// this list of conditions and the following disclaimer in the documentation
// and/or other materials provided with the distribution.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
// ARE DISCLAIMED.
// IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
// OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
// HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
// LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
// OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
// SUCH DAMAGE.
//
#include "tr_hash.hh"
#include <memory>
#include <stdexcept>
#include <sstream>
#include <string>
#include <vector>
#include <gnutls/crypto.h>
namespace tr_hash
{
class hash::impl
{
public:
impl (const std::string &name);
~impl () = default;
impl (const impl &) = delete;
impl& operator= (const impl &) = delete;
impl (impl &&) = default;
impl& operator= (impl &&) = default;
explicit operator bool ();
std::vector<unsigned char>
calc (const std::vector<unsigned char> &input);
std::string oid ();
private:
gnutls_digest_algorithm_t algo_ = GNUTLS_DIG_UNKNOWN;
};
hash::impl::impl (const std::string &name)
{
if (name == "sha256")
algo_ = GNUTLS_DIG_SHA256;
else if (name == "sha384")
algo_ = GNUTLS_DIG_SHA384;
else if (name == "sha512")
algo_ = GNUTLS_DIG_SHA512;
else if (name == "sha1")
algo_ = GNUTLS_DIG_SHA1;
else if (name == "ripemd160")
algo_ = GNUTLS_DIG_RMD160;
}
hash::impl::operator bool ()
{
if (algo_ == GNUTLS_DIG_UNKNOWN)
return false;
return true;
}
std::vector<unsigned char>
hash::impl::calc (const std::vector<unsigned char> &input)
{
auto len {gnutls_hash_get_len (algo_)};
if (len == 0)
throw std::runtime_error("GnuTLS error: gnutls_hash_get_len: failed");
std::vector<unsigned char> retval (len);
auto ret {gnutls_hash_fast (algo_, input.data (), input.size (),
retval.data ())};
if (ret < 0)
{
std::stringstream ss;
ss << "GnuTLS error: gnutls_hash_fast:" << gnutls_strerror (ret);
throw std::runtime_error (ss.str ().c_str ());
}
return retval;
}
std::string hash::impl::oid ()
{
switch (algo_)
{
case GNUTLS_DIG_SHA256:
return "2.16.840.1.101.3.4.2.1";
case GNUTLS_DIG_SHA384:
return "2.16.840.1.101.3.4.2.2";
case GNUTLS_DIG_SHA512:
return "2.16.840.1.101.3.4.2.3";
case GNUTLS_DIG_SHA1:
return "1.3.14.3.2.26";
case GNUTLS_DIG_RMD160:
return "1.3.36.3.2.1";
default:
break;
}
return "";
}
hash::hash (const std::string &name):
pimpl_ (new hash::impl (name))
{
}
hash::~hash () = default;
hash::hash (hash &&) = default;
hash& hash::operator= (hash &&) = default;
hash::operator bool ()
{
return static_cast<bool> (*pimpl_);
}
std::vector<unsigned char>
hash::calc (const std::vector<unsigned char> &input)
{
return pimpl_->calc (input);
}
std::string hash::oid ()
{
return pimpl_->oid ();
}
}
//
// tr_libtasn1: C++ class library for libtasn1
// https://gist.github.com/trueroad/77165de4a367da4eaae7038658262063
//
// tr_libtasn1.cc:
// Implementation for tr_libtasn1
//
// Copyright (C) 2019, 2020 Masamichi Hosoda.
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions
// are met:
//
// * Redistributions of source code must retain the above copyright notice,
// this list of conditions and the following disclaimer.
//
// * Redistributions in binary form must reproduce the above copyright notice,
// this list of conditions and the following disclaimer in the documentation
// and/or other materials provided with the distribution.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
// ARE DISCLAIMED.
// IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
// OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
// HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
// LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
// OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
// SUCH DAMAGE.
//
#include "tr_libtasn1.hh"
#include <iostream>
#include <memory>
#include <sstream>
#include <string>
#include <stdexcept>
#include <libtasn1.h>
namespace tr_libtasn1
{
asn1_definition::asn1_definition (const asn1_static_node * array)
{
asn1_node definitions = nullptr;
char errorDescription[ASN1_MAX_ERROR_DESCRIPTION_SIZE];
int asn1_result = asn1_array2tree (array, &definitions, errorDescription);
if (asn1_result != ASN1_SUCCESS)
{
std::stringstream ss;
ss << "tr_libtasn1: asn1_array2tree error: "
<< asn1_strerror (asn1_result)
<< ", description: " << errorDescription;
throw std::runtime_error (ss.str ().c_str ());
}
definitions_.reset (definitions,
[] (asn1_node d)
{
asn1_delete_structure (&d);
});
}
asn1_definition::~asn1_definition () = default;
asn1_definition::asn1_definition (const asn1_definition &) = default;
asn1_definition& asn1_definition::operator= (const asn1_definition &) =
default;
asn1_definition::asn1_definition (asn1_definition &&) = default;
asn1_definition& asn1_definition::operator= (asn1_definition &&) =
default;
asn1_structure asn1_definition::create_element (const std::string &name)
{
return asn1_structure (*this, name);
}
asn1_definition::operator asn1_node () const
{
return definitions_.get ();
}
asn1_structure::asn1_structure (const asn1_definition &definition,
const std::string &name):
definition_ (definition)
{
int asn1_result = asn1_create_element (definition_,
name.c_str (),
&structure_);
if (asn1_result != ASN1_SUCCESS)
{
std::stringstream ss;
ss << "tr_libtasn1: asn1_create_element \""
<< name << "\" error: "
<< asn1_strerror (asn1_result);
throw std::runtime_error (ss.str ().c_str ());
}
}
asn1_structure::~asn1_structure ()
{
asn1_delete_structure (&structure_);
}
asn1_structure::asn1_structure (asn1_structure &&) = default;
asn1_structure& asn1_structure::operator= (asn1_structure &&) = default;
void asn1_structure::delete_element (const std::string &name)
{
int asn1_result = asn1_delete_element (structure_,
name.c_str ());
if (asn1_result != ASN1_SUCCESS)
{
std::stringstream ss;
ss << "tr_libtasn1: asn1_delete_element \""
<< name << "\" error: "
<< asn1_strerror (asn1_result);
throw std::runtime_error (ss.str ().c_str ());
}
}
int asn1_structure::number_of_elements (const std::string &name)
{
int num {0};
int asn1_result = asn1_number_of_elements (structure_,
name.c_str (),
&num);
if (asn1_result != ASN1_SUCCESS)
{
std::stringstream ss;
ss << "tr_libtasn1: asn1_number_of_elements \""
<< name << "\" error: "
<< asn1_strerror (asn1_result);
throw std::runtime_error (ss.str ().c_str ());
}
return num;
}
int asn1_structure::number_of_elements_optional (const std::string &name)
{
int num {0};
int asn1_result = asn1_number_of_elements (structure_,
name.c_str (),
&num);
if (asn1_result == ASN1_ELEMENT_NOT_FOUND)
return 0;
else if (asn1_result != ASN1_SUCCESS)
{
std::stringstream ss;
ss << "tr_libtasn1: asn1_number_of_elements \""
<< name << "\" error: "
<< asn1_strerror (asn1_result);
throw std::runtime_error (ss.str ().c_str ());
}
return num;
}
void asn1_structure::copy_node (const std::string &dst_name,
const std::string &src_name)
{
int asn1_result = asn1_copy_node (structure_,
dst_name.c_str (),
structure_,
src_name.c_str ());
if (asn1_result != ASN1_SUCCESS)
{
std::stringstream ss;
ss << "tr_libtasn1: asn1_copy_node dst \""
<< dst_name << "\", src \"" << src_name << "\" error: "
<< asn1_strerror (asn1_result);
throw std::runtime_error (ss.str ().c_str ());
}
}
void asn1_structure::copy_node (const std::string &dst_name,
const asn1_structure &src_structure,
const std::string &src_name)
{
int asn1_result = asn1_copy_node (structure_,
dst_name.c_str (),
src_structure,
src_name.c_str ());
if (asn1_result != ASN1_SUCCESS)
{
std::stringstream ss;
ss << "tr_libtasn1: asn1_copy_node dst \""
<< dst_name << "\", src \"" << src_name << "\" error: "
<< asn1_strerror (asn1_result);
throw std::runtime_error (ss.str ().c_str ());
}
}
void asn1_structure::copy_node_optional (const std::string &dst_name,
const std::string &src_name)
{
int asn1_result = asn1_copy_node (structure_,
dst_name.c_str (),
structure_,
src_name.c_str ());
if (asn1_result == ASN1_ELEMENT_NOT_FOUND)
{
asn1_result = asn1_delete_element (structure_, dst_name.c_str ());
if (asn1_result != ASN1_SUCCESS)
{
std::stringstream ss;
ss << "tr_libtasn1: asn1_delete_element dst \""
<< dst_name << "\" error: "
<< asn1_strerror (asn1_result);
throw std::runtime_error (ss.str ().c_str ());
}
}
else if (asn1_result != ASN1_SUCCESS)
{
std::stringstream ss;
ss << "tr_libtasn1: asn1_copy_node dst \""
<< dst_name << "\", src \"" << src_name << "\" error: "
<< asn1_strerror (asn1_result);
throw std::runtime_error (ss.str ().c_str ());
}
}
void asn1_structure::write_value (const std::string &name,
const char *value,
int len)
{
int asn1_result = asn1_write_value (structure_,
name.c_str (),
value,
len);
if (asn1_result != ASN1_SUCCESS)
{
std::stringstream ss;
ss << "tr_libtasn1: asn1_write_value char* \""
<< name << "\" error: "
<< asn1_strerror (asn1_result);
throw std::runtime_error (ss.str ().c_str ());
}
}
void asn1_structure::write_value (const std::string &name,
const std::vector<unsigned char> &value)
{
int asn1_result = asn1_write_value (structure_,
name.c_str (),
value.data (),
value.size ());
if (asn1_result != ASN1_SUCCESS)
{
std::stringstream ss;
ss << "tr_libtasn1: asn1_write_value binary \""
<< name << "\" error: "
<< asn1_strerror (asn1_result);
throw std::runtime_error (ss.str ().c_str ());
}
}
std::vector<unsigned char>
asn1_structure::read_value_binary (const std::string &name)
{
std::vector<unsigned char> retval;
int len {0};
int asn1_result = asn1_read_value (structure_,
name.c_str (),
nullptr,
&len);
if (asn1_result == ASN1_MEM_ERROR)
{
retval.resize (len);
asn1_result = asn1_read_value (structure_,
name.c_str (),
retval.data (),
&len);
}
if (asn1_result != ASN1_SUCCESS)
{
std::stringstream ss;
ss << "tr_libtasn1: asn1_read_value binary \""
<< name << "\" error: "
<< asn1_strerror (asn1_result);
throw std::runtime_error (ss.str ().c_str ());
}
return retval;
}
std::string
asn1_structure::read_value_string (const std::string &name)
{
std::string retval;
int len {0};
int asn1_result = asn1_read_value (structure_,
name.c_str (),
nullptr,
&len);
if (asn1_result == ASN1_MEM_ERROR)
{
retval.resize (len);
asn1_result = asn1_read_value (structure_,
name.c_str (),
&retval[0],
&len);
}
if (asn1_result != ASN1_SUCCESS)
{
std::stringstream ss;
ss << "tr_libtasn1: asn1_read_value string \""
<< name << "\" error: "
<< asn1_strerror (asn1_result);
throw std::runtime_error (ss.str ().c_str ());
}
if (retval.back () == 0)
retval.pop_back (); // remove zero termination
return retval;
}
int asn1_structure::read_value_int (const std::string &name)
{
auto buff {read_value_binary (name)};
if (buff.size () > sizeof (int))
{
throw std::runtime_error ("tr_libtasn1: "
"asn1_structure::read_value_int: "
"size overflow");
}
int retval {*(reinterpret_cast<const char*> (&buff[0]))};
for (int i = 1; i < buff.size (); ++i)
{
retval = (retval << 8) | buff[i];
}
return retval;
}
std::vector<unsigned char>
asn1_structure::der_coding (const std::string &name)
{
std::vector<unsigned char> retval;
int der_len {0};
char errorDescription[ASN1_MAX_ERROR_DESCRIPTION_SIZE];
int asn1_result = asn1_der_coding (structure_,
name.c_str (),
nullptr,
&der_len,
errorDescription);
if (asn1_result == ASN1_MEM_ERROR)
{
retval.resize (der_len);
asn1_result = asn1_der_coding (structure_,
name.c_str (),
retval.data (),
&der_len,
errorDescription);
}
if (asn1_result != ASN1_SUCCESS)
{
std::stringstream ss;
ss << "tr_libtasn1: asn1_der_coding \""
<< name << "\" error: "
<< asn1_strerror (asn1_result)
<< ", description: " << errorDescription;
throw std::runtime_error (ss.str ().c_str ());
}
return retval;
}
void asn1_structure::der_decoding (const std::vector<unsigned char> &buffer)
{
char errorDescription[ASN1_MAX_ERROR_DESCRIPTION_SIZE];
int asn1_result = asn1_der_decoding (&structure_,
buffer.data (),
buffer.size (),
errorDescription);
if (asn1_result != ASN1_SUCCESS)
{
std::stringstream ss;
ss << "tr_libtasn1: asn1_der_decoding error: "
<< asn1_strerror (asn1_result)
<< ", description: " << errorDescription;
throw std::runtime_error (ss.str ().c_str ());
}
}
asn1_structure::operator asn1_node () const
{
return structure_;
}
}
//
// tr_libtasn1: C++ class library for libtasn1
// https://gist.github.com/trueroad/77165de4a367da4eaae7038658262063
//
// tr_libtasn1.hh:
// Header file for tr_libtasn1
//
// Copyright (C) 2019, 2020 Masamichi Hosoda.
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions
// are met:
//
// * Redistributions of source code must retain the above copyright notice,
// this list of conditions and the following disclaimer.
//
// * Redistributions in binary form must reproduce the above copyright notice,
// this list of conditions and the following disclaimer in the documentation
// and/or other materials provided with the distribution.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
// ARE DISCLAIMED.
// IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
// OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
// HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
// LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
// OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
// SUCH DAMAGE.
//
#ifndef INCLUDE_GUARD_TR_LIBTASN1_HH
#define INCLUDE_GUARD_TR_LIBTASN1_HH
#include <memory>
#include <vector>
struct asn1_node_st;
typedef asn1_node_st *asn1_node;
struct asn1_static_node_st;
typedef struct asn1_static_node_st asn1_static_node;
namespace tr_libtasn1
{
class asn1_structure;
class asn1_definition
{
public:
asn1_definition (const asn1_static_node * /* array */);
~asn1_definition ();
asn1_definition (const asn1_definition &);
asn1_definition& operator= (const asn1_definition &);
asn1_definition (asn1_definition &&);
asn1_definition& operator= (asn1_definition &&);
asn1_structure create_element (const std::string & /* name */);
operator asn1_node () const;
private:
std::shared_ptr<asn1_node_st> definitions_;
};
class asn1_structure
{
public:
asn1_structure (const asn1_definition & /* definition */,
const std::string & /* name */);
~asn1_structure ();
asn1_structure (const asn1_structure &) = delete;
asn1_structure& operator= (const asn1_structure &) = delete;
asn1_structure (asn1_structure &&);
asn1_structure& operator= (asn1_structure &&);
void delete_element (const std::string & /* name */);
int number_of_elements (const std::string & /* name */);
int number_of_elements_optional (const std::string & /* name */);
void copy_node (const std::string & /* dst_name */,
const std::string & /* src_name */);
void copy_node (const std::string & /* dst_name */,
const asn1_structure & /* src_structure */,
const std::string & /* src_name */);
void copy_node_optional (const std::string & /* dst_name */,
const std::string & /* src_name */);
void write_value (const std::string & /* name */,
const char * /* value */,
int len = 0);
void write_value (const std::string & /* name */,
const std::vector<unsigned char> & /* value */);
std::vector<unsigned char>
read_value_binary (const std::string & /* name */);
std::string
read_value_string (const std::string & /* name */);
int read_value_int (const std::string & /* name */);
std::vector<unsigned char> der_coding (const std::string & /* name */);
void der_decoding (const std::vector<unsigned char> & /* buffer */);
operator asn1_node () const;
private:
asn1_definition definition_;
asn1_node structure_ = nullptr;
};
}
#endif // INCLUDE_GUARD_TR_LIBTASN1_HH
//
// Utility for binary files / data
//
// tr_util_binary.hh:
// Header file / implementation
//
// Copyright (C) 2019, 2020 Masamichi Hosoda.
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions
// are met:
//
// * Redistributions of source code must retain the above copyright notice,
// this list of conditions and the following disclaimer.
//
// * Redistributions in binary form must reproduce the above copyright notice,
// this list of conditions and the following disclaimer in the documentation
// and/or other materials provided with the distribution.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
// ARE DISCLAIMED.
// IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
// OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
// HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
// LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
// OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
// SUCH DAMAGE.
//
#ifndef INCLUDE_GUARD_TR_UTIL_BINARY_HH
#define INCLUDE_GUARD_TR_UTIL_BINARY_HH
#include <fstream>
#include <iomanip>
#include <stdexcept>
#include <sstream>
#include <string>
#include <vector>
namespace tr_util
{
inline
std::string binary_hex (const std::vector<unsigned char> &buff)
{
std::stringstream ss;
ss << std::hex;
for (int i = 0; i < buff.size (); ++i)
{
if ((i % 16) == 0 && i)
ss << std::endl;
ss << std::setw (2) << std::setfill ('0')
<< static_cast<unsigned int> (buff[i]) << " ";
}
ss << std::endl;
return ss.str ();
}
inline
std::vector<unsigned char> fileload_binary (const std::string &filename)
{
std::ifstream ifs (filename, std::ios::binary);
if (!ifs)
throw std::runtime_error ("tr_util::fileload_binary: "
"std::ifstream failed");
ifs.seekg (0, std::ios::end);
auto eof {ifs.tellg ()};
ifs.clear ();
ifs.seekg (0, std::ios::beg);
std::vector<unsigned char> buff (eof);
ifs.read (reinterpret_cast<char*> (buff.data ()), buff.size ());
return buff;
}
inline void filesave (const std::string &filename,
const std::vector<unsigned char> &buff)
{
std::ofstream ofs (filename, std::ios::binary);
if (!ofs)
throw std::runtime_error ("tr_util::filesave: "
"std::ofstream failed");
ofs.write (reinterpret_cast<const char*> (buff.data ()), buff.size ());
}
}
#endif // INCLUDE_GUARD_TR_UTIL_BINARY_HH
-- From RFC 3161 --
PKIXTSP {iso(1) identified-organization(3) dod(6) internet(1)
security(5) mechanisms(5) pkix(7) id-mod(0) id-mod-tsp(13)}
DEFINITIONS IMPLICIT TAGS ::=
BEGIN
-- 2.4.1
TimeStampReq ::= SEQUENCE {
version INTEGER { v1(1) },
messageImprint MessageImprint,
--a hash algorithm OID and the hash value of the data to be
--time-stamped
reqPolicy TSAPolicyId OPTIONAL,
nonce INTEGER OPTIONAL,
certReq BOOLEAN DEFAULT FALSE,
extensions [0] IMPLICIT Extensions OPTIONAL }
MessageImprint ::= SEQUENCE {
hashAlgorithm AlgorithmIdentifier,
hashedMessage OCTET STRING }
TSAPolicyId ::= OBJECT IDENTIFIER
-- 2.4.2
TimeStampResp ::= SEQUENCE {
status PKIStatusInfo,
timeStampToken TimeStampToken OPTIONAL }
-- The status is based on the definition of status
-- in section 3.2.3 of [RFC2510]
PKIStatusInfo ::= SEQUENCE {
status PKIStatus,
statusString PKIFreeText OPTIONAL,
failInfo PKIFailureInfo OPTIONAL }
PKIStatus ::= INTEGER {
granted (0),
-- when the PKIStatus contains the value zero a TimeStampToken, as
-- requested, is present.
grantedWithMods (1),
-- when the PKIStatus contains the value one a TimeStampToken,
-- with modifications, is present.
rejection (2),
waiting (3),
revocationWarning (4),
-- this message contains a warning that a revocation is
-- imminent
revocationNotification (5)
-- notification that a revocation has occurred
}
-- When the TimeStampToken is not present
-- failInfo indicates the reason why the
-- time-stamp request was rejected and
-- may be one of the following values.
PKIFailureInfo ::= BIT STRING {
badAlg (0),
-- unrecognized or unsupported Algorithm Identifier
badRequest (2),
-- transaction not permitted or supported
badDataFormat (5),
-- the data submitted has the wrong format
timeNotAvailable (14),
-- the TSA's time source is not available
unacceptedPolicy (15),
-- the requested TSA policy is not supported by the TSA.
unacceptedExtension (16),
-- the requested extension is not supported by the TSA.
addInfoNotAvailable (17),
-- the additional information requested could not be understood
-- or is not available
systemFailure (25)
-- the request cannot be handled due to system failure
}
TimeStampToken ::= ContentInfo
-- contentType is id-signedData as defined in [CMS]
-- content is SignedData as defined in([CMS])
-- eContentType within SignedData is id-ct-TSTInfo
-- eContent within SignedData is TSTInfo
TSTInfo ::= SEQUENCE {
version INTEGER { v1(1) },
policy TSAPolicyId,
messageImprint MessageImprint,
-- MUST have the same value as the similar field in
-- TimeStampReq
serialNumber INTEGER,
-- Time-Stamping users MUST be ready to accommodate integers
-- up to 160 bits.
genTime GeneralizedTime,
accuracy Accuracy OPTIONAL,
ordering BOOLEAN DEFAULT FALSE,
nonce INTEGER OPTIONAL,
-- MUST be present if the similar field was present
-- in TimeStampReq. In that case it MUST have the same value.
tsa [0] GeneralName OPTIONAL,
extensions [1] IMPLICIT Extensions OPTIONAL }
Accuracy ::= SEQUENCE {
seconds INTEGER OPTIONAL,
millis [0] INTEGER (1..999) OPTIONAL,
micros [1] INTEGER (1..999) OPTIONAL }
-- ... --
-- From RFC 2459 / 3280 / 5280 --
-- ... --
Extensions ::= SEQUENCE SIZE (1..MAX) OF Extension
Extension ::= SEQUENCE {
extnID OBJECT IDENTIFIER,
critical BOOLEAN DEFAULT FALSE,
extnValue OCTET STRING
-- contains the DER encoding of an ASN.1 value
-- corresponding to the extension type identified
-- by extnID
}
-- ... --
AlgorithmIdentifier ::= SEQUENCE {
algorithm OBJECT IDENTIFIER,
parameters ANY DEFINED BY algorithm OPTIONAL }
-- contains a value of the type
-- registered for use with the
-- algorithm object identifier value
-- ... --
-- From RFC 2510 / 4210 --
-- ... --
PKIFreeText ::= SEQUENCE SIZE (1..MAX) OF UTF8String
-- text encoded as UTF-8 String [RFC3629] (note: each
-- UTF8String MAY include an [RFC3066] language tag
-- to indicate the language of the contained text
-- see [RFC2482] for details)
-- ... --
-- From RFC 2630 / 3369 / 3852 / 5652 --
-- ... --
-- Cryptographic Message Syntax
ContentInfo ::= SEQUENCE {
contentType ContentType,
content [0] EXPLICIT ANY DEFINED BY contentType }
ContentType ::= OBJECT IDENTIFIER
-- ... --
-- From RFC 5280 --
-- ... --
GeneralName ::= CHOICE {
otherName [0] AnotherName,
rfc822Name [1] IA5String,
dNSName [2] IA5String,
x400Address [3] ORAddress,
directoryName [4] Name,
ediPartyName [5] EDIPartyName,
uniformResourceIdentifier [6] IA5String,
iPAddress [7] OCTET STRING,
registeredID [8] OBJECT IDENTIFIER }
-- ... --
-- dummy --
-- RFC 5280
AnotherName ::= SEQUENCE OF ANY
ORAddress ::= SEQUENCE OF ANY
Name ::= SEQUENCE OF ANY
EDIPartyName ::= SEQUENCE OF ANY
END
#if HAVE_CONFIG_H
# include "config.h"
#endif
#include <libtasn1.h>
const asn1_static_node ts_asn1_tab[] = {
{ "PKIXTSP", 536875024, NULL },
{ NULL, 1610612748, NULL },
{ "iso", 1073741825, "1"},
{ "identified-organization", 1073741825, "3"},
{ "dod", 1073741825, "6"},
{ "internet", 1073741825, "1"},
{ "security", 1073741825, "5"},
{ "mechanisms", 1073741825, "5"},
{ "pkix", 1073741825, "7"},
{ "id-mod", 1073741825, "0"},
{ "id-mod-tsp", 1, "13"},
{ "TimeStampReq", 1610612741, NULL },
{ "version", 1610874883, NULL },
{ "v1", 1, "1"},
{ "messageImprint", 1073741826, "MessageImprint"},
{ "reqPolicy", 1073758210, "TSAPolicyId"},
{ "nonce", 1073758211, NULL },
{ "certReq", 1610645508, NULL },
{ NULL, 131081, NULL },
{ "extensions", 536895490, "Extensions"},
{ NULL, 4104, "0"},
{ "MessageImprint", 1610612741, NULL },
{ "hashAlgorithm", 1073741826, "AlgorithmIdentifier"},
{ "hashedMessage", 7, NULL },
{ "TSAPolicyId", 1073741836, NULL },
{ "TimeStampResp", 1610612741, NULL },
{ "status", 1073741826, "PKIStatusInfo"},
{ "timeStampToken", 16386, "TimeStampToken"},
{ "PKIStatusInfo", 1610612741, NULL },
{ "status", 1073741826, "PKIStatus"},
{ "statusString", 1073758210, "PKIFreeText"},
{ "failInfo", 16386, "PKIFailureInfo"},
{ "PKIStatus", 1610874883, NULL },
{ "granted", 1073741825, "0"},
{ "grantedWithMods", 1073741825, "1"},
{ "rejection", 1073741825, "2"},
{ "waiting", 1073741825, "3"},
{ "revocationWarning", 1073741825, "4"},
{ "revocationNotification", 1, "5"},
{ "PKIFailureInfo", 1610874886, NULL },
{ "badAlg", 1073741825, "0"},
{ "badRequest", 1073741825, "2"},
{ "badDataFormat", 1073741825, "5"},
{ "timeNotAvailable", 1073741825, "14"},
{ "unacceptedPolicy", 1073741825, "15"},
{ "unacceptedExtension", 1073741825, "16"},
{ "addInfoNotAvailable", 1073741825, "17"},
{ "systemFailure", 1, "25"},
{ "TimeStampToken", 1073741826, "ContentInfo"},
{ "TSTInfo", 1610612741, NULL },
{ "version", 1610874883, NULL },
{ "v1", 1, "1"},
{ "policy", 1073741826, "TSAPolicyId"},
{ "messageImprint", 1073741826, "MessageImprint"},
{ "serialNumber", 1073741827, NULL },
{ "genTime", 1073741861, NULL },
{ "accuracy", 1073758210, "Accuracy"},
{ "ordering", 1610645508, NULL },
{ NULL, 131081, NULL },
{ "nonce", 1073758211, NULL },
{ "tsa", 1610637314, "GeneralName"},
{ NULL, 4104, "0"},
{ "extensions", 536895490, "Extensions"},
{ NULL, 4104, "1"},
{ "Accuracy", 1610612741, NULL },
{ "seconds", 1073758211, NULL },
{ "millis", 1611161603, NULL },
{ NULL, 1073745928, "0"},
{ "1", 10, "999"},
{ "micros", 537419779, NULL },
{ NULL, 1073745928, "1"},
{ "1", 10, "999"},
{ "Extensions", 1612709899, NULL },
{ "MAX", 1074266122, "1"},
{ NULL, 2, "Extension"},
{ "Extension", 1610612741, NULL },
{ "extnID", 1073741836, NULL },
{ "critical", 1610645508, NULL },
{ NULL, 131081, NULL },
{ "extnValue", 7, NULL },
{ "AlgorithmIdentifier", 1610612741, NULL },
{ "algorithm", 1073741836, NULL },
{ "parameters", 541081613, NULL },
{ "algorithm", 1, NULL },
{ "PKIFreeText", 1612709899, NULL },
{ "MAX", 1074266122, "1"},
{ NULL, 34, NULL },
{ "ContentInfo", 1610612741, NULL },
{ "contentType", 1073741826, "ContentType"},
{ "content", 541073421, NULL },
{ NULL, 1073743880, "0"},
{ "contentType", 1, NULL },
{ "ContentType", 1073741836, NULL },
{ "GeneralName", 1610612754, NULL },
{ "otherName", 1610620930, "AnotherName"},
{ NULL, 4104, "0"},
{ "rfc822Name", 1610620957, NULL },
{ NULL, 4104, "1"},
{ "dNSName", 1610620957, NULL },
{ NULL, 4104, "2"},
{ "x400Address", 1610620930, "ORAddress"},
{ NULL, 4104, "3"},
{ "directoryName", 1610620930, "Name"},
{ NULL, 4104, "4"},
{ "ediPartyName", 1610620930, "EDIPartyName"},
{ NULL, 4104, "5"},
{ "uniformResourceIdentifier", 1610620957, NULL },
{ NULL, 4104, "6"},
{ "iPAddress", 1610620935, NULL },
{ NULL, 4104, "7"},
{ "registeredID", 536879116, NULL },
{ NULL, 4104, "8"},
{ "AnotherName", 1610612747, NULL },
{ NULL, 13, NULL },
{ "ORAddress", 1610612747, NULL },
{ NULL, 13, NULL },
{ "Name", 1610612747, NULL },
{ NULL, 13, NULL },
{ "EDIPartyName", 536870923, NULL },
{ NULL, 13, NULL },
{ NULL, 0, NULL }
};
//
// Time stamp (RFC 3161) tools
// https://gist.github.com/trueroad/40072532a258b3519c8f6beabe829b0c
//
// ts_req.cc:
// Time stamp request generator
//
// Copyright (C) 2019 Masamichi Hosoda.
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions
// are met:
//
// * Redistributions of source code must retain the above copyright notice,
// this list of conditions and the following disclaimer.
//
// * Redistributions in binary form must reproduce the above copyright notice,
// this list of conditions and the following disclaimer in the documentation
// and/or other materials provided with the distribution.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
// ARE DISCLAIMED.
// IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
// OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
// HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
// LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
// OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
// SUCH DAMAGE.
//
#include <fstream>
#include <iostream>
#include <stdexcept>
#include <string>
#include <vector>
#include "tr_gnutls_init.hh"
#include "tr_util_binary.hh"
#include "ts_req_gen_req.hh"
extern "C" const asn1_static_node ts_asn1_tab[];
int main (int argc, char *argv[])
{
std::cout
<< "Time stamp request (RFC 3161) generator"
<< std::endl
<< "Copyright (C) 2019 Masamichi Hosoda"
<< std::endl << std::endl;
if (argc != 4)
{
std::cout
<< "usage: " << argv[0]
<< " DIGEST (in)TO-BE-SIGNED.bin (out)TIME-STAMP-REQUEST.bin"
<< std::endl << std::endl
<< " DIGEST: sha256|sha384|sha512|sha1|ripemd160"
<< std::endl;
return 1;
}
std::string digest {argv[1]};
std::string filename_in {argv[2]};
std::string filename_out {argv[3]};
std::cout
<< "digest: " << digest << std::endl
<< "input filename: " << filename_in << std::endl
<< "output filename: " << filename_out << std::endl << std::endl;
try
{
tr_gnutls::global_init g;
auto req {gen_req (digest, tr_util::fileload_binary (filename_in))};
if (req.size () == 0)
{
std::cout << "generate failed" << std::endl;
return 1;
}
std::cout << "der_coding succeeded" << std::endl
<< tr_util::binary_hex (req) << std::flush;
std::cout << std::endl
<< "writing request file \"" << filename_out
<< "\"..." << std::endl;
tr_util::filesave (filename_out, req);
}
catch (std::runtime_error &e)
{
std::cout << e.what () << std::endl;
return 1;
}
std::cout << std::endl << "complete" << std::endl;
return 0;
}
//
// Time stamp (RFC 3161) tools
// https://gist.github.com/trueroad/40072532a258b3519c8f6beabe829b0c
//
// ts_req_gen_req.hh:
// Time stamp request generation implementation
//
// Copyright (C) 2019 Masamichi Hosoda.
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions
// are met:
//
// * Redistributions of source code must retain the above copyright notice,
// this list of conditions and the following disclaimer.
//
// * Redistributions in binary form must reproduce the above copyright notice,
// this list of conditions and the following disclaimer in the documentation
// and/or other materials provided with the distribution.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
// ARE DISCLAIMED.
// IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
// OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
// HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
// LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
// OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
// SUCH DAMAGE.
//
#ifndef INCLUDE_GUARD_TS_REQ_GEN_REQ_HH
#define INCLUDE_GUARD_TS_REQ_GEN_REQ_HH
#include <gnutls/crypto.h>
#include "tr_gnutls_rnd.hh"
#include "tr_hash.hh"
#include "tr_libtasn1.hh"
extern "C" const asn1_static_node ts_asn1_tab[];
inline
std::vector<unsigned char>
gen_nonce ()
{
auto nonce {tr_gnutls::rnd (GNUTLS_RND_NONCE, 8)};
while (nonce[0] == 0 &&
nonce.size () > 1 && (nonce[1] & 0x80) == 0)
nonce.erase (nonce.begin ());
while (nonce[0] == 0xff &&
nonce.size () > 1 && (nonce[1] & 0x80) != 0)
nonce.erase (nonce.begin ());
return nonce;
}
inline
std::vector<unsigned char>
gen_req (const std::string &digest, const std::vector<unsigned char> &data)
{
tr_hash::hash h (digest);
if (!h)
{
throw std::runtime_error ("unknown digest");
}
tr_libtasn1::asn1_definition d (ts_asn1_tab);
auto s {d.create_element ("PKIXTSP.TimeStampReq")};
s.write_value ("messageImprint.hashAlgorithm.algorithm",
h.oid ().c_str ());
auto md {h.calc (data)};
s.write_value ("messageImprint.hashedMessage", md);
s.write_value ("nonce", gen_nonce ());
s.write_value ("version", "1");
s.write_value ("certReq", "TRUE");
s.write_value ("messageImprint.hashAlgorithm.parameters", nullptr);
s.write_value ("reqPolicy", nullptr);
s.write_value ("extensions", nullptr);
return s.der_coding ("");
}
#endif // INCLUDE_GUARD_TS_REQ_GEN_REQ_HH
//
// Time stamp (RFC 3161) tools
// https://gist.github.com/trueroad/40072532a258b3519c8f6beabe829b0c
//
// ts_resp.cc:
// Time stamp response parser
//
// Copyright (C) 2019 Masamichi Hosoda.
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions
// are met:
//
// * Redistributions of source code must retain the above copyright notice,
// this list of conditions and the following disclaimer.
//
// * Redistributions in binary form must reproduce the above copyright notice,
// this list of conditions and the following disclaimer in the documentation
// and/or other materials provided with the distribution.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
// ARE DISCLAIMED.
// IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
// OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
// HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
// LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
// OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
// SUCH DAMAGE.
//
#include <fstream>
#include <iostream>
#include <stdexcept>
#include <string>
#include <vector>
#include "tr_libtasn1.hh"
#include "tr_util_binary.hh"
extern "C" const asn1_static_node ts_asn1_tab[];
extern "C" const asn1_static_node cms_asn1_tab[];
int main (int argc, char *argv[])
{
std::cout
<< "Time stamp response (RFC 3161) parser"
<< std::endl
<< "Copyright (C) 2019 Masamichi Hosoda"
<< std::endl << std::endl;
if (argc != 4)
{
std::cout
<< "usage: " << argv[0]
<< " (in)TIME-STAMP-REQUEST.bin (in)TIME-STAMP-RESPONSE.bin"
" (out)TIME-STAMP-TOKEN.p7s"
<< std::endl;
return 1;
}
std::string filename_req {argv[1]};
std::string filename_resp {argv[2]};
std::string filename_token {argv[3]};
std::cout
<< "request filename: " << filename_req << std::endl
<< "response filename: " << filename_resp << std::endl
<< "token filename: " << filename_token << std::endl << std::endl;
try
{
tr_libtasn1::asn1_definition d_ts (ts_asn1_tab);
auto s_req {d_ts.create_element ("PKIXTSP.TimeStampReq")};
s_req.der_decoding (tr_util::fileload_binary (filename_req));
std::cout << "TimeStampReq:" << std::endl
<< " messageImprint:" << std::endl
<< " hashAlgorithm:" << std::endl
<< " algorithm: ";
auto algo_req {s_req.read_value_string
("messageImprint.hashAlgorithm.algorithm")};
std::cout << algo_req << std::endl;
std::cout << " hashedMessage:" << std::endl;
auto hash_req {s_req.read_value_binary
("messageImprint.hashedMessage")};
std::cout << tr_util::binary_hex (hash_req) << std::flush;
std::cout << " nonce:" << std::endl;
auto nonce_req {s_req.read_value_binary ("nonce")};
std::cout << tr_util::binary_hex (nonce_req) << std::flush;
std::cout << std::endl;
auto s_resp {d_ts.create_element ("PKIXTSP.TimeStampResp")};
s_resp.der_decoding (tr_util::fileload_binary (filename_resp));
std::cout << "TimeStampResp:" << std::endl
<< " status:" << std::endl
<< " status: ";
auto resp_status {s_resp.read_value_int ("status.status")};
std::cout << resp_status << std::endl;
if (! (resp_status == 0 || resp_status == 1))
{
std::cout << "failed" << std::endl;
return 1;
}
std::cout << " timeStampToken:" << std::endl
<< " contentType: ";
auto content_type
{s_resp.read_value_string ("timeStampToken.contentType")};
std::cout << content_type << std::endl;
if (content_type != "1.2.840.113549.1.7.2")
{
std::cout << "contentType different" << std::endl;
return 1;
}
auto signed_data {s_resp.read_value_binary ("timeStampToken.content")};
tr_libtasn1::asn1_definition d_cms (cms_asn1_tab);
auto s_sign {d_cms.create_element
("CryptographicMessageSyntax2004.SignedData")};
s_sign.der_decoding (signed_data);
std::cout << " content: (SignedData)" << std::endl
<< " encapContentInfo:" << std::endl
<< " eContentType: ";
auto econtent_type
{s_sign.read_value_string ("encapContentInfo.eContentType")};
std::cout << econtent_type << std::endl;
if (econtent_type != "1.2.840.113549.1.9.16.1.4")
{
std::cout << "eContentType different" << std::endl;
return 1;
}
auto tst_info {s_sign.read_value_binary ("encapContentInfo.eContent")};
auto s_tst {d_ts.create_element ("PKIXTSP.TSTInfo")};
s_tst.der_decoding (tst_info);
std::cout << " eContent: (TSTInfo)" << std::endl
<< " messageImprint:" << std::endl
<< " hashAlgorithm:" << std::endl
<< " algorithm: ";
auto algo_resp {s_req.read_value_string
("messageImprint.hashAlgorithm.algorithm")};
std::cout << algo_resp << std::endl;
if (algo_req != algo_resp)
{
std::cout << "algorithm different" << std::endl;
return 1;
}
std::cout << " hashedMessage:" << std::endl;
auto hash_resp {s_req.read_value_binary
("messageImprint.hashedMessage")};
std::cout << tr_util::binary_hex (hash_resp) << std::flush;
if (hash_req != hash_resp)
{
std::cout << "hash different" << std::endl;
return 1;
}
std::cout << " nonce:" << std::endl;
auto nonce_resp {s_tst.read_value_binary ("nonce")};
std::cout << tr_util::binary_hex (nonce_resp) << std::flush;
if (nonce_req != nonce_resp)
{
std::cout << "nonce different" << std::endl;
return 1;
}
auto token {s_resp.der_coding ("timeStampToken")};
std::cout << std::endl
<< "writing token file \"" << filename_token
<< "\"..." << std::endl;
tr_util::filesave (filename_token, token);
}
catch (std::runtime_error &e)
{
std::cout << e.what () << std::endl;
return 1;
}
std::cout << std::endl << "complete" << std::endl;
return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment