File: skecdsa.rb

package info (click to toggle)
ruby-ssh-data 1.3.0-2
  • links: PTS, VCS
  • area: main
  • in suites: bookworm, forky, sid, trixie
  • size: 184 kB
  • sloc: ruby: 1,483; makefile: 4
file content (64 lines) | stat: -rw-r--r-- 2,109 bytes parent folder | download
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
module SSHData
  module PublicKey
    class SKECDSA < ECDSA
      include SecurityKey
      attr_reader :application

      OPENSSL_CURVE_NAME_FOR_CURVE = {
        NISTP256 => "prime256v1",
      }

      def self.check_algorithm!(algo, curve)
        unless algo == ALGO_SKECDSA256
          raise DecodeError, "bad algorithm: #{algo.inspect}"
        end

        unless algo == "sk-ecdsa-sha2-#{curve}@openssh.com"
          raise DecodeError, "bad curve: #{curve.inspect}"
        end
      end

      def initialize(algo:, curve:, public_key:, application:)
        @application = application
        super(algo: algo, curve: curve, public_key: public_key)
      end

      # RFC4253 binary encoding of the public key.
      #
      # Returns a binary String.
      def rfc4253
        Encoding.encode_fields(
          [:string, algo],
          [:string, curve],
          [:string, public_key_bytes],
          [:string, application],
        )
      end

      def verify(signed_data, signature, **opts)
        opts = DEFAULT_SK_VERIFY_OPTS.merge(opts)
        unknown_opts = opts.keys - DEFAULT_SK_VERIFY_OPTS.keys
        raise UnsupportedError, "Verification options #{unknown_opts.inspect} are not supported." unless unknown_opts.empty?

        sig_algo, raw_sig, sk_flags, blob = build_signing_blob(application, signed_data, signature)
        self.class.check_algorithm!(sig_algo, curve)

        openssl_sig = self.class.openssl_signature(raw_sig)
        digest = DIGEST_FOR_CURVE[curve]

        result = openssl.verify(digest.new, openssl_sig, blob)

        # We don't know that the flags are correct until after we've validated the signature
        # which embeds the flags, so always verify the signature first.
        return false if opts[:user_presence_required] && (sk_flags & SK_FLAG_USER_PRESENCE != SK_FLAG_USER_PRESENCE)
        return false if opts[:user_verification_required] && (sk_flags & SK_FLAG_USER_VERIFICATION != SK_FLAG_USER_VERIFICATION)

        result
      end

      def ==(other)
        super && other.application == application
      end
    end
  end
end