Skip to content

Commit

Permalink
add v2 schemes for pkcs1 and pkcs1 pss schemes
Browse files Browse the repository at this point in the history
- related to #377
  • Loading branch information
ezekg committed Oct 2, 2020
1 parent 944c066 commit 9d1faab
Show file tree
Hide file tree
Showing 10 changed files with 518 additions and 14 deletions.
61 changes: 47 additions & 14 deletions app/models/license.rb
Original file line number Diff line number Diff line change
Expand Up @@ -197,11 +197,15 @@ def encrypt_key
when "RSA_2048_PKCS1_ENCRYPT"
generate_pkcs1_encrypted_key!
when "RSA_2048_PKCS1_SIGN"
generate_pkcs1_signed_key!
generate_pkcs1_signed_key! version: 1
when "RSA_2048_PKCS1_PSS_SIGN"
generate_pkcs1_pss_signed_key!
generate_pkcs1_pss_signed_key! version: 1
when "RSA_2048_JWT_RS256"
generate_jwt_rs256_key!
when "RSA_2048_PKCS1_SIGN_V2"
generate_pkcs1_signed_key! version: 2
when "RSA_2048_PKCS1_PSS_SIGN_V2"
generate_pkcs1_pss_signed_key! version: 2
end

raise ActiveRecord::RecordInvalid if key.nil?
Expand Down Expand Up @@ -236,32 +240,61 @@ def generate_unencrypted_key!
def generate_pkcs1_encrypted_key!
if key.bytesize <= RSA_MAX_BYTE_SIZE
priv = OpenSSL::PKey::RSA.new account.private_key
enc = priv.private_encrypt key
encrypted_key = priv.private_encrypt key
encoded_key = Base64.urlsafe_encode64 encrypted_key

self.key = Base64.urlsafe_encode64 enc
self.key = encoded_key
else
errors.add :key, :byte_size_exceeded, message: "key exceeds maximum byte length (max size of #{RSA_MAX_BYTE_SIZE} bytes)"
end
end

def generate_pkcs1_signed_key!
def generate_pkcs1_signed_key!(version:)
priv = OpenSSL::PKey::RSA.new account.private_key
sig = priv.sign OpenSSL::Digest::SHA256.new, key
res = nil

encoded_key = Base64.urlsafe_encode64 key
encoded_sig = Base64.urlsafe_encode64 sig
case version
when 1
sig = priv.sign OpenSSL::Digest::SHA256.new, key

self.key = "#{encoded_key}.#{encoded_sig}"
encoded_key = Base64.urlsafe_encode64 key
encoded_sig = Base64.urlsafe_encode64 sig

res = "#{encoded_key}.#{encoded_sig}"
when 2
encoded_key = Base64.urlsafe_encode64 key
signing_data = "key/#{encoded_key}"
sig = priv.sign OpenSSL::Digest::SHA256.new, signing_data
encoded_sig = Base64.urlsafe_encode64 sig

res = "#{signing_data}.#{encoded_sig}"
end

self.key = res
end

def generate_pkcs1_pss_signed_key!
def generate_pkcs1_pss_signed_key!(version:)
priv = OpenSSL::PKey::RSA.new account.private_key
sig = priv.sign_pss OpenSSL::Digest::SHA256.new, key, salt_length: :max, mgf1_hash: "SHA256"
res = nil

encoded_key = Base64.urlsafe_encode64 key
encoded_sig = Base64.urlsafe_encode64 sig
case version
when 1
sig = priv.sign_pss OpenSSL::Digest::SHA256.new, key, salt_length: :max, mgf1_hash: "SHA256"

encoded_key = Base64.urlsafe_encode64 key
encoded_sig = Base64.urlsafe_encode64 sig

res = "#{encoded_key}.#{encoded_sig}"
when 2
encoded_key = Base64.urlsafe_encode64 key
signing_data = "key/#{encoded_key}"
sig = priv.sign_pss OpenSSL::Digest::SHA256.new, signing_data, salt_length: :max, mgf1_hash: "SHA256"
encoded_sig = Base64.urlsafe_encode64 sig

res = "#{signing_data}.#{encoded_sig}"
end

self.key = "#{encoded_key}.#{encoded_sig}"
self.key = res
end

def generate_jwt_rs256_key!
Expand Down
2 changes: 2 additions & 0 deletions app/models/policy.rb
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@ class Policy < ApplicationRecord
RSA_2048_PKCS1_SIGN
RSA_2048_PKCS1_PSS_SIGN
RSA_2048_JWT_RS256
RSA_2048_PKCS1_SIGN_V2
RSA_2048_PKCS1_PSS_SIGN_V2
].freeze

SEARCH_ATTRIBUTES = %i[id name metadata].freeze
Expand Down
127 changes: 127 additions & 0 deletions features/api/v1/licenses/actions/validations.feature
Original file line number Diff line number Diff line change
Expand Up @@ -1900,6 +1900,41 @@ Feature: License validation actions
And sidekiq should have 1 "metric" job
And sidekiq should have 1 "request-log" job

Scenario: An admin validates a license using scheme RSA_2048_PKCS1_SIGN_V2
Given I am an admin of account "test1"
And the current account is "test1"
And the current account has 1 "webhook-endpoint"
And the current account has 1 "policy"
And the current account has 1 "license" using "RSA_2048_PKCS1_SIGN_V2"
And I use an authentication token
When I send a POST request to "/accounts/test1/licenses/$0/actions/validate"
Then the response status should be "200"
And the JSON response should contain a "license"
And the JSON response should contain meta which includes the following:
"""
{ "valid": true, "detail": "is valid", "constant": "VALID" }
"""
And sidekiq should have 1 "webhook" job
And sidekiq should have 1 "metric" job
And sidekiq should have 1 "request-log" job

Scenario: An admin validates a license using scheme RSA_2048_PKCS1_PSS_SIGN_V2
Given I am an admin of account "test1"
And the current account is "test1"
And the current account has 1 "webhook-endpoint"
And the current account has 1 "license" using "RSA_2048_PKCS1_PSS_SIGN_V2"
And I use an authentication token
When I send a POST request to "/accounts/test1/licenses/$0/actions/validate"
Then the response status should be "200"
And the JSON response should contain a "license"
And the JSON response should contain meta which includes the following:
"""
{ "valid": true, "detail": "is valid", "constant": "VALID" }
"""
And sidekiq should have 1 "webhook" job
And sidekiq should have 1 "metric" job
And sidekiq should have 1 "request-log" job

# Key validation
Scenario: Key validation endpoint should be inaccessible when account is disabled
Given the account "test1" is canceled
Expand Down Expand Up @@ -2245,6 +2280,98 @@ Feature: License validation actions
And sidekiq should have 0 "metric" jobs
And sidekiq should have 1 "request-log" job

Scenario: Anonymous validates a license using scheme RSA_2048_PKCS1_SIGN_V2 by key
Given the current account is "test1"
And the current account has 1 "webhook-endpoint"
And the current account has 1 "license" using "RSA_2048_PKCS1_SIGN_V2"
When I send a POST request to "/accounts/test1/licenses/actions/validate-key" with the following:
"""
{
"meta": {
"key": "$licenses[0].key",
"encrypted": false
}
}
"""
Then the response status should be "200"
And the JSON response should contain a "license"
And the JSON response should contain meta which includes the following:
"""
{ "valid": true, "detail": "is valid", "constant": "VALID" }
"""
And sidekiq should have 1 "webhook" job
And sidekiq should have 1 "metric" job
And sidekiq should have 1 "request-log" job

Scenario: Anonymous validates a license using scheme RSA_2048_PKCS1_SIGN_V2 by key using the legacy encrypted flag
Given the current account is "test1"
And the current account has 1 "webhook-endpoint"
And the current account has 1 "license" using "RSA_2048_PKCS1_SIGN_V2"
When I send a POST request to "/accounts/test1/licenses/actions/validate-key" with the following:
"""
{
"meta": {
"key": "$licenses[0].key",
"encrypted": true
}
}
"""
Then the response status should be "200"
And the JSON response should not contain a "license"
And the JSON response should contain meta which includes the following:
"""
{ "valid": false, "detail": "does not exist", "constant": "NOT_FOUND" }
"""
And sidekiq should have 0 "webhook" jobs
And sidekiq should have 0 "metric" jobs
And sidekiq should have 1 "request-log" job

Scenario: Anonymous validates a license using scheme RSA_2048_PKCS1_PSS_SIGN_V2 by key
Given the current account is "test1"
And the current account has 1 "webhook-endpoint"
And the current account has 1 "license" using "RSA_2048_PKCS1_PSS_SIGN_V2"
When I send a POST request to "/accounts/test1/licenses/actions/validate-key" with the following:
"""
{
"meta": {
"key": "$licenses[0].key",
"encrypted": false
}
}
"""
Then the response status should be "200"
And the JSON response should contain a "license"
And the JSON response should contain meta which includes the following:
"""
{ "valid": true, "detail": "is valid", "constant": "VALID" }
"""
And sidekiq should have 1 "webhook" job
And sidekiq should have 1 "metric" job
And sidekiq should have 1 "request-log" job

Scenario: Anonymous validates a license using scheme RSA_2048_PKCS1_PSS_SIGN_V2 by key using the legacy encrypted flag
Given the current account is "test1"
And the current account has 1 "webhook-endpoint"
And the current account has 1 "license" using "RSA_2048_PKCS1_PSS_SIGN_V2"
When I send a POST request to "/accounts/test1/licenses/actions/validate-key" with the following:
"""
{
"meta": {
"key": "$licenses[0].key",
"encrypted": true
}
}
"""
Then the response status should be "200"
And the JSON response should not contain a "license"
And the JSON response should contain meta which includes the following:
"""
{ "valid": false, "detail": "does not exist", "constant": "NOT_FOUND" }
"""
And sidekiq should have 0 "webhook" jobs
And sidekiq should have 0 "metric" jobs
And sidekiq should have 1 "request-log" job

Scenario: Anonymous validates a valid license by key from a pool
Given the current account is "test1"
And the current account has 1 "webhook-endpoint"
Expand Down
Loading

0 comments on commit 9d1faab

Please sign in to comment.