diff --git a/.editorconfig b/.editorconfig index 16ff5720c..111c6ec90 100644 --- a/.editorconfig +++ b/.editorconfig @@ -10,5 +10,5 @@ indent_size = 2 indent_style = space trim_trailing_whitespace = true -[*.{ico,keep,pdf,svg}] +[*.{ico,keep,pdf,svg,der}] insert_final_newline = false diff --git a/app/lib/asn1/timestamp.rb b/app/lib/asn1/timestamp.rb new file mode 100644 index 000000000..6dd65e4db --- /dev/null +++ b/app/lib/asn1/timestamp.rb @@ -0,0 +1,25 @@ +class ASN1::Timestamp + ## Poor man’s rfc3161 timestamp decoding + # This works, as of 2019-05, for timestamps delivered by the universign POST api. + # We should properly access the ASN1 contents using the sequence and tags structure. + # However: + # * It’s hard to do right. + # * We currently don’t require it for proper operation; timestamps are never exposed to users. + # * There’s an ongoing PR https://github.com/ruby/openssl/pull/204 for proper timestamp decoding in the ruby openssl library; let’s use OpenSSL::TS once it exists. + + def self.timestampInfo(asn1timestamp) + asn1 = OpenSSL::ASN1.decode(asn1timestamp) + tstInfo = OpenSSL::ASN1.decode(asn1.value[1].value[0].value[2].value[1].value[0].value) + tstInfo + end + + def self.signature_time(asn1timestamp) + tstInfo = timestampInfo(asn1timestamp) + tstInfo.value[4].value + end + + def self.signed_digest(asn1timestamp) + tstInfo = timestampInfo(asn1timestamp) + tstInfo.value[2].value[1].value.unpack1('H*') + end +end diff --git a/spec/fixtures/files/bill_signature/signature.der b/spec/fixtures/files/bill_signature/signature.der new file mode 100644 index 000000000..9adcc9a7e Binary files /dev/null and b/spec/fixtures/files/bill_signature/signature.der differ diff --git a/spec/lib/asn1/timestamp_spec.rb b/spec/lib/asn1/timestamp_spec.rb new file mode 100644 index 000000000..3ae0d6272 --- /dev/null +++ b/spec/lib/asn1/timestamp_spec.rb @@ -0,0 +1,19 @@ +require 'spec_helper' + +describe ASN1::Timestamp do + let(:asn1timestamp) { File.read('spec/fixtures/files/bill_signature/signature.der') } + + describe '.timestamp_time' do + subject { described_class.signature_time(asn1timestamp) } + + it { is_expected.to eq Time.zone.parse('2019-04-30 15:30:20 UTC') } + end + + describe '.timestamp_signed_data' do + subject { described_class.signed_digest(asn1timestamp) } + + let(:data) { Digest::SHA256.hexdigest('CECI EST UN BLOB') } + + it { is_expected.to eq data } + end +end