Class: Sphragis::Providers::FortifyWebcryptoProvider

Inherits:
BaseProvider
  • Object
show all
Defined in:
lib/sphragis/providers/fortify_webcrypto_provider.rb

Overview

Fortify by Peculiar Ventures Provider Uses Fortify WebCrypto bridge to access hardware tokens

Requirements:

License: MIT (FREE for all use)

Constant Summary collapse

FORTIFY_DEFAULT_URL =
"https://localhost:31337"

Instance Attribute Summary

Attributes inherited from BaseProvider

#config

Instance Method Summary collapse

Methods inherited from BaseProvider

#connected?, #provider_name

Constructor Details

#initialize(config = {}) ⇒ FortifyWebcryptoProvider

Initialize Fortify WebCrypto provider

Parameters:

  • config (Hash) (defaults to: {})

    Configuration options

    • api_url: Fortify API URL (default: https://localhost:31337)
    • token_pin: Hardware token PIN
    • certificate_id: Certificate identifier on token
    • verify_ssl: Verify SSL (default: false for localhost)


32
33
34
35
36
37
38
39
40
41
# File 'lib/sphragis/providers/fortify_webcrypto_provider.rb', line 32

def initialize(config = {})
  super
  @config = {
    api_url: config[:api_url] || FORTIFY_DEFAULT_URL,
    token_pin: config[:token_pin],
    certificate_id: config[:certificate_id],
    verify_ssl: config[:verify_ssl] || false
  }
  @http = setup_http_client
end

Instance Method Details

#certificateObject

Raises:



108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
# File 'lib/sphragis/providers/fortify_webcrypto_provider.rb', line 108

def certificate
  raise ProviderError, "Not connected to Fortify" unless connected?

  cert_id = @config[:certificate_id] || find_signing_certificate
  cert_info = get_certificate_info(cert_id)

  {
    provider: "fortify_webcrypto",
    subject: cert_info[:subject],
    issuer: cert_info[:issuer],
    serial: cert_info[:serial],
    not_before: cert_info[:not_before],
    not_after: cert_info[:not_after],
    key_usage: cert_info[:key_usage],
    hardware_backed: true
  }
end

#connectObject



43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
# File 'lib/sphragis/providers/fortify_webcrypto_provider.rb', line 43

def connect
  validate_configuration!

  # Check if Fortify is running
  unless fortify_running?
    raise ProviderError, "Fortify app is not running. Start it with: fortify"
  end

  # List available providers (tokens)
  providers = list_providers

  if providers.empty?
    raise ProviderError, "No hardware tokens detected. Please insert your token."
  end

  # Get the first available provider
  @provider_id = providers.first["id"]

  # Login to token with PIN
  (@provider_id, @config[:token_pin])

  @session = {
    connected: true,
    provider: "fortify_webcrypto",
    provider_id: @provider_id,
    fortify_url: @config[:api_url]
  }

  # Cache signing certificate for x509_certificate (requires @session to be set)
  cert_id = @config[:certificate_id] || find_signing_certificate
  @x509_cert = fetch_x509_cert(cert_id)

  true
rescue StandardError => e
  raise ProviderError, "Failed to connect to Fortify: #{e.message}"
end

#disconnectObject



80
81
82
83
84
85
# File 'lib/sphragis/providers/fortify_webcrypto_provider.rb', line 80

def disconnect
  # Logout from token
  logout(@session[:provider_id]) if @session
  @session = nil
  true
end

#fortify_infoHash

Get Fortify version info

Returns:

  • (Hash)


157
158
159
# File 'lib/sphragis/providers/fortify_webcrypto_provider.rb', line 157

def fortify_info
  make_request(:get, "/info")
end

#fortify_running?Boolean

Check if Fortify app is running

Returns:

  • (Boolean)


148
149
150
151
152
153
# File 'lib/sphragis/providers/fortify_webcrypto_provider.rb', line 148

def fortify_running?
  response = make_request(:get, "/info")
  response.is_a?(Hash) && response["name"] == "fortify"
rescue StandardError
  false
end

#sign(data) ⇒ Object



87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
# File 'lib/sphragis/providers/fortify_webcrypto_provider.rb', line 87

def sign(data)
  raise ProviderError, "Not connected to Fortify" unless connected?

  # Get certificate from token
  cert_id = @config[:certificate_id] || find_signing_certificate

  # Sign data using WebCrypto API
  signature_result = sign_with_webcrypto(cert_id, data)

  {
    provider: "fortify_webcrypto",
    algorithm: signature_result[:algorithm],
    signature: signature_result[:signature],
    timestamp: Time.now.utc.iso8601,
    certificate_id: cert_id,
    hardware_token: true
  }
rescue StandardError => e
  raise ProviderError, "Failed to sign with Fortify: #{e.message}"
end

#sign_bytes(data) ⇒ Object



130
131
132
133
134
135
136
137
138
# File 'lib/sphragis/providers/fortify_webcrypto_provider.rb', line 130

def sign_bytes(data)
  raise ProviderError, "Not connected to Fortify" unless connected?

  cert_id = @config[:certificate_id] || find_signing_certificate
  result = sign_with_webcrypto(cert_id, data)
  Base64.strict_decode64(result[:signature])
rescue StandardError => e
  raise ProviderError, "Failed to sign bytes with Fortify: #{e.message}"
end

#validate_configuration!Object

Raises:



126
127
128
# File 'lib/sphragis/providers/fortify_webcrypto_provider.rb', line 126

def validate_configuration!
  raise ProviderError, "Token PIN not configured" if @config[:token_pin].nil?
end

#x509_certificateObject

Raises:



140
141
142
143
144
# File 'lib/sphragis/providers/fortify_webcrypto_provider.rb', line 140

def x509_certificate
  raise ProviderError, "Not connected to Fortify" unless connected?

  @x509_cert
end