lib/origami/signature.rb in origami-2.0.4 vs lib/origami/signature.rb in origami-2.1.0

- old
+ new

@@ -47,21 +47,11 @@ data = extract_signed_data(digsig) signature = digsig[:Contents] subfilter = digsig.SubFilter.value - case subfilter - when Signature::DigitalSignature::PKCS7_DETACHED - Signature.verify_pkcs7_detached_signature(data, signature, store, flags) - - - when Signature::DigitalSignature::PKCS7_SHA1 - Signature.verify_pkcs7_sha1_signature(data, signature, store, flags) - - else - raise NotImplementedError, "Unsupported method #{digsig.SubFilter}" - end + Signature.verify(subfilter.to_s, data, signature, store, flags) end # # Sign the document with the given key and x509 certificate. # _certificate_:: The X509 certificate containing the public key. @@ -73,11 +63,11 @@ # _location_:: Signature location. # _contact_:: Signer contact. # _reason_:: Signing reason. # def sign(certificate, key, - method: "adbe.pkcs7.detached", + method: Signature::PKCS7_DETACHED, ca: [], annotation: nil, issuer: nil, location: nil, contact: nil, @@ -97,45 +87,10 @@ unless annotation.nil? or annotation.is_a?(Annotation::Widget::Signature) raise TypeError, "Expected a Annotation::Widget::Signature object." end - case method - when 'adbe.pkcs7.detached' - signfield_size = -> (crt, pkey, certs) do - OpenSSL::PKCS7.sign( - crt, - pkey, - "", - certs, - OpenSSL::PKCS7::DETACHED | OpenSSL::PKCS7::BINARY - ).to_der.size - end - - when 'adbe.pkcs7.sha1' - signfield_size = -> (crt, pkey, certs) do - OpenSSL::PKCS7.sign( - crt, - pkey, - Digest::SHA1.digest(''), - certs, - OpenSSL::PKCS7::BINARY - ).to_der.size - end - - when 'adbe.x509.rsa_sha1' - signfield_size = -> (_crt, pkey, _certs) do - pkey.private_encrypt( - Digest::SHA1.digest('') - ).size - end - raise NotImplementedError, "Unsupported method #{method.inspect}" - - else - raise NotImplementedError, "Unsupported method #{method.inspect}" - end - digsig = Signature::DigitalSignature.new.set_indirect(true) if annotation.nil? annotation = Annotation::Widget::Signature.new annotation.Rect = Rectangle[:llx => 0.0, :lly => 0.0, :urx => 0.0, :ury => 0.0] @@ -144,22 +99,23 @@ annotation.V = digsig add_fields(annotation) self.Catalog.AcroForm.SigFlags = InteractiveForm::SigFlags::SIGNATURES_EXIST | InteractiveForm::SigFlags::APPEND_ONLY - digsig.Type = :Sig #:nodoc: - digsig.Contents = HexaString.new("\x00" * signfield_size[certificate, key, ca]) #:nodoc: - digsig.Filter = :"Adobe.PPKLite" #:nodoc: - digsig.SubFilter = Name.new(method) #:nodoc: - digsig.ByteRange = [0, 0, 0, 0] #:nodoc: + digsig.Type = :Sig + digsig.Contents = HexaString.new("\x00" * Signature::required_size(method, certificate, key, ca)) + digsig.Filter = :"Adobe.PPKLite" + digsig.SubFilter = Name.new(method) + digsig.ByteRange = [0, 0, 0, 0] digsig.Name = issuer digsig.Location = HexaString.new(location) if location digsig.ContactInfo = HexaString.new(contact) if contact digsig.Reason = HexaString.new(reason) if reason - if method == 'adbe.x509.rsa_sha1' + # PKCS1 signatures require a Cert entry. + if method == Signature::PKCS1_RSA_SHA1 digsig.Cert = if ca.empty? HexaString.new(certificate.to_der) else [ HexaString.new(certificate.to_der) ] + ca.map{ |crt| HexaString.new(crt.to_der) } @@ -195,34 +151,14 @@ file_data = output() signable_data = file_data[digsig.ByteRange[0],digsig.ByteRange[1]] + file_data[digsig.ByteRange[2],digsig.ByteRange[3]] - signature = - case method - when 'adbe.pkcs7.detached' - OpenSSL::PKCS7.sign( - certificate, - key, - signable_data, - ca, - OpenSSL::PKCS7::DETACHED | OpenSSL::PKCS7::BINARY - ).to_der - - when 'adbe.pkcs7.sha1' - OpenSSL::PKCS7.sign( - certificate, - key, - Digest::SHA1.digest(signable_data), - ca, - OpenSSL::PKCS7::BINARY - ).to_der - - when 'adbe.x509.rsa_sha1' - key.private_encrypt(Digest::SHA1.digest(signable_data)) - end - + # + # Computes and inserts the signature. + # + signature = Signature.compute(method, signable_data, certificate, key, ca) digsig.Contents[0, signature.size] = signature # # No more modification are allowed after signing. # @@ -246,19 +182,12 @@ # Enable the document Usage Rights. # _rights_:: list of rights defined in UsageRights::Rights # def enable_usage_rights(cert, pkey, *rights) - signfield_size = -> (crt, key, ca) do - OpenSSL::PKCS7.sign( - crt, - key, - '', - ca, - OpenSSL::PKCS7::DETACHED | OpenSSL::PKCS7::BINARY - ).to_der.size - end + # Always uses a detached PKCS7 signature for UR. + method = Signature::PKCS7_DETACHED # # Load key pair # key = pkey.is_a?(OpenSSL::PKey::RSA) ? pkey : OpenSSL::PKey::RSA.new(pkey) @@ -270,25 +199,25 @@ digsig = Signature::DigitalSignature.new.set_indirect(true) self.Catalog.AcroForm ||= InteractiveForm.new #self.Catalog.AcroForm.SigFlags = InteractiveForm::SigFlags::APPEND_ONLY - digsig.Type = :Sig #:nodoc: - digsig.Contents = HexaString.new("\x00" * signfield_size[certificate, key, []]) #:nodoc: - digsig.Filter = :"Adobe.PPKLite" #:nodoc: - digsig.Name = "ARE Acrobat Product v8.0 P23 0002337" #:nodoc: - digsig.SubFilter = :"adbe.pkcs7.detached" #:nodoc: - digsig.ByteRange = [0, 0, 0, 0] #:nodoc: + digsig.Type = :Sig + digsig.Contents = HexaString.new("\x00" * Signature.required_size(method, certificate, key, [])) + digsig.Filter = :"Adobe.PPKLite" + digsig.Name = "ARE Acrobat Product v8.0 P23 0002337" + digsig.SubFilter = Name.new(method ) + digsig.ByteRange = [0, 0, 0, 0] - sigref = Signature::Reference.new #:nodoc: - sigref.Type = :SigRef #:nodoc: - sigref.TransformMethod = :UR3 #:nodoc: + sigref = Signature::Reference.new + sigref.Type = :SigRef + sigref.TransformMethod = :UR3 sigref.Data = self.Catalog sigref.TransformParams = UsageRights::TransformParams.new - sigref.TransformParams.P = true #:nodoc: - sigref.TransformParams.Type = :TransformParams #:nodoc: + sigref.TransformParams.P = true + sigref.TransformParams.Type = :TransformParams sigref.TransformParams.V = UsageRights::TransformParams::VERSION rights.each do |right| sigref.TransformParams[right.first] ||= [] sigref.TransformParams[right.first].concat(right[1..-1]) @@ -328,17 +257,11 @@ file_data = output() signable_data = file_data[digsig.ByteRange[0],digsig.ByteRange[1]] + file_data[digsig.ByteRange[2],digsig.ByteRange[3]] - signature = OpenSSL::PKCS7.sign( - certificate, - key, - signable_data, - [], - OpenSSL::PKCS7::DETACHED | OpenSSL::PKCS7::BINARY - ).to_der + signature = Signature.compute(method, signable_data, certificate, key, []) digsig.Contents[0, signature.size] = signature # # No more modification are allowed after signing. # @@ -397,26 +320,57 @@ field :UR3, :Type => Dictionary, :Version => "1.6" end module Signature - # Verifies a PKCS7 detached signature. - def self.verify_pkcs7_detached_signature(data, signature, store, flags) - pkcs7 = OpenSSL::PKCS7.new(signature) - raise SignatureError, "Not a PKCS7 detached signature" unless pkcs7.detached? + PKCS1_RSA_SHA1 = "adbe.x509.rsa_sha1" + PKCS7_SHA1 = "adbe.pkcs7.sha1" + PKCS7_DETACHED = "adbe.pkcs7.detached" - flags |= OpenSSL::PKCS7::DETACHED - pkcs7.verify([], store, data, flags) + def self.verify(method, data, signature, store, flags) + case method + when PKCS7_DETACHED + pkcs7 = OpenSSL::PKCS7.new(signature) + raise SignatureError, "Not a PKCS7 detached signature" unless pkcs7.detached? + flags |= OpenSSL::PKCS7::DETACHED + pkcs7.verify([], store, data, flags) + + when PKCS7_SHA1 + pkcs7 = OpenSSL::PKCS7.new(signature) + pkcs7.verify([], store, nil, flags) and pkcs7.data == Digest::SHA1.digest(data) + + else + raise NotImplementedError, "Unsupported signature method #{method.inspect}" + end end - # Verifies a PKCS7-SHA1 signature. - def self.verify_pkcs7_sha1_signature(data, signature, store, flags) - pkcs7 = OpenSSL::PKCS7.new(signature) - pkcs7.verify([], store, nil, flags) and pkcs7.data == Digest::SHA1.digest(data) + # + # Computes the required size in bytes for storing the signature. + # + def self.required_size(method, certificate, key, ca) + self.compute(method, "", certificate, key, ca).size end # + # Computes the signature using the specified subfilter method. + # + def self.compute(method, data, certificate, key, ca) + case method + when PKCS7_DETACHED + OpenSSL::PKCS7.sign(certificate, key, data, ca, OpenSSL::PKCS7::DETACHED | OpenSSL::PKCS7::BINARY).to_der + + when PKCS7_SHA1 + OpenSSL::PKCS7.sign(certificate, key, Digest::SHA1.digest(data), ca, OpenSSL::PKCS7::BINARY).to_der + + when PKCS1_RSA_SHA1 + key.sign(OpenSSL::Digest::SHA1.new, data) + else + raise NotImplementedError, "Unsupported signature method #{method.inspect}" + end + end + + # # Class representing a signature which can be embedded in DigitalSignature dictionary. # It must be a direct object. # class Reference < Dictionary include StandardObject @@ -503,13 +457,9 @@ # # Class representing a digital signature. # class DigitalSignature < Dictionary include StandardObject - - PKCS1_RSA_SHA1 = :"adbe.x509.rsa_sha1" - PKCS7_SHA1 = :"adbe.pkcs7.sha1" - PKCS7_DETACHED = :"adbe.pkcs7.detached" field :Type, :Type => Name, :Default => :Sig field :Filter, :Type => Name, :Default => :"Adobe.PPKLite", :Required => true field :SubFilter, :Type => Name field :Contents, :Type => String, :Required => true