ruby-jsonld-signatures 0.0.10

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 4935f61cd06bb5e3d67e927527fb9f2b0965c28a61a94c32313dcfa7c39b7a9d
4
+ data.tar.gz: 603d4cd7d729f4f9d5a903f613cb0b4a75c32a0b726cd7d8dc4e0f4871a857f8
5
+ SHA512:
6
+ metadata.gz: 6c04d6231e6c1b0eb9257160f7fed3c26f64e2913a3aec70589d5fcceeae3538fd79ac2d2030025a31094f0442350f5c6afbfeecd6f1caf0ecbdd52db3404a05
7
+ data.tar.gz: 39c321c7477204ec0301f74a0f3e67625e25da1db90eaabcd056f7192da57660683cb69a5ead0a75933a4a08a22ca7010f1ebeb59f75439afed3b8d6ca1c3f65
data/AUTHORS ADDED
@@ -0,0 +1,2 @@
1
+ * Brian Sletten <brian@bosatsu.net>
2
+ * John Callahan <jcallahan@acm.org>
data/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2015 Accreditrust Technologies, LLC.
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in
13
+ all copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
+ THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,199 @@
1
+ This gem is an implementation of the JSON-LD Signatures specification
2
+ in Ruby that supports the following encryption options:
3
+
4
+ * RSA
5
+ * Ed25519
6
+
7
+ Demo
8
+ ----
9
+
10
+ See [an example](https://ldsigdemo.herokuapp.com/) of the gem in action. The source code for the demo is [here](https://github.com/johncallahan/ldsigdemo).
11
+
12
+ Getting Started
13
+ ---------------
14
+
15
+ Add the gem to your Gemfile:
16
+
17
+ ```ruby
18
+ gem 'ruby-jsonld-signatures'
19
+ ```
20
+
21
+ then run `bundle install`
22
+
23
+ Development
24
+ -----------
25
+
26
+ Clone this repo, bundle and run the rspec tests:
27
+
28
+ ```shell
29
+ git clone https://github.com/johncallahan/ruby-jsonld-signatures.git
30
+ bundle install
31
+ rspec
32
+ ```
33
+
34
+ Description
35
+ -----------
36
+
37
+ Consider the following JSON-LD document:
38
+
39
+ ```json
40
+ {
41
+ "@context": [ "https://w3id.org/credentials/v1","https://w3id.org/security/v1"],
42
+ "type" : [ "Credential" ],
43
+ "claim" : {
44
+ "id" : "did:v1:test:nym:JApJf12r82Pe6PBJ3gJAAwo8F7uDnae6B4ab9EFQ7XXk",
45
+ "publicKey" : "did:v1:test:nym:JApJf12r82Pe6PBJ3gJAAwo8F7uDnae6B4ab9EFQ7XXk#authn-key-1"
46
+ },
47
+ "issuer" : "did:v1:test:nym:JApJf12r82Pe6PBJ3gJAAwo8F7uDnae6B4ab9EFQ7XXk",
48
+ "issued" : "2018-03-15T00:00:00Z"
49
+ }
50
+ ```
51
+
52
+ The goal of [Linked Data Signatures](https://w3c-dvcg.github.io/ld-signatures/) is to
53
+ cryptographically "sign" a JSON-LD document such that the the order of
54
+ key/pairs within the JSON-LD document does not matter. In other words,
55
+ the signature value of the JSON content above would be:
56
+
57
+ ```
58
+ t/T2Wv335B2guVYW88I9uWKEdrE3HFddrXt14AVo9aD9yr5BAbGJT5eQbVGdG+O0Hn6RU9IYgi1o15/F3x37Ag==
59
+ ```
60
+
61
+ The following document is equivalent to the JSON-LD document above even
62
+ though more whitespace is added and the key/value pairs (even in
63
+ embedded blocks) are in different order but their values are equal:
64
+
65
+ ```json
66
+ {
67
+ "issued" : "2018-03-15T00:00:00Z",
68
+
69
+ "issuer" : "did:v1:test:nym:JApJf12r82Pe6PBJ3gJAAwo8F7uDnae6B4ab9EFQ7XXk",
70
+ "claim" : {
71
+ "publicKey" : "did:v1:test:nym:JApJf12r82Pe6PBJ3gJAAwo8F7uDnae6B4ab9EFQ7XXk#authn-key-1",
72
+ "id" : "did:v1:test:nym:JApJf12r82Pe6PBJ3gJAAwo8F7uDnae6B4ab9EFQ7XXk"
73
+ },
74
+
75
+ "type" : [ "Credential" ],
76
+ "@context": [ "https://w3id.org/credentials/v1","https://w3id.org/security/v1"]
77
+ }
78
+
79
+ ```
80
+
81
+ After generating the signature value for the JSON-LD document, the
82
+ signature value is appended to the document with additional metadata:
83
+
84
+ ```json
85
+ {
86
+ "@context":["https://w3id.org/credentials/v1","https://w3id.org/security/v1"],
87
+ "type":["Credential"],
88
+ "claim":{
89
+ "id":"did:v1:test:nym:JApJf12r82Pe6PBJ3gJAAwo8F7uDnae6B4ab9EFQ7XXk",
90
+ "publicKey":"did:v1:test:nym:JApJf12r82Pe6PBJ3gJAAwo8F7uDnae6B4ab9EFQ7XXk#authn-key-1"
91
+ },
92
+ "issuer":"did:v1:test:nym:JApJf12r82Pe6PBJ3gJAAwo8F7uDnae6B4ab9EFQ7XXk",
93
+ "issued":"2018-03-15T00:00:00Z",
94
+ "signature":{
95
+ "type":"Ed25519Signature2018",
96
+ "creator":"did:v1:test:nym:JApJf12r82Pe6PBJ3gJAAwo8F7uDnae6B4ab9EFQ7XXk#authn-key-1",
97
+ "created":"2018-03-15T00:00:00Z",
98
+ "signatureValue":"t/T2Wv335B2guVYW88I9uWKEdrE3HFddrXt14AVo9aD9yr5BAbGJT5eQbVGdG+O0Hn6RU9IYgi1o15/F3x37Ag=="
99
+ }
100
+ }
101
+ ```
102
+
103
+ This signed content can be presented to other parties such that any
104
+ key/value pair change to the JSON content (not the order or
105
+ whitespace) can be detected. It is useful in [DID Auth](https://github.com/WebOfTrustInfo/rebooting-the-web-of-trust-spring2018/blob/master/final-documents/did-auth.md) where a
106
+ user (via their browser or mobile device) holds a private key and
107
+ needs to provide [verifiable credentials](https://github.com/WebOfTrustInfo/rwot7/blob/master/topics-and-advance-readings/verifiable-credentials-primer.md) to a replying party or
108
+ service provider. In the case of DID Auth, the relying party can
109
+ verify the signature by resolving the DID (via a [universal
110
+ resolver](https://github.com/decentralized-identity/universal-resolver)) to obtain the public key from a blockchain ([Veres
111
+ One](https://github.com/veres-one/veres-one) in this case).
112
+
113
+ The process of signing a JSON-LD document includes:
114
+
115
+ * resolving the context vocabularies (i.e., fetching them via their URLs in the @context]
116
+ * normalizing (or sometimes called 'canonicalizing') the document
117
+ * determining the signature value with a private key (using RSA or Ed25519)
118
+ * embedding the signature JSON with the metadata and signature value (not part of the JSON-LD document)
119
+
120
+ Verifying a signed JSON-LD document includes:
121
+
122
+ * extracting the signature block from the JSON-LD document (remove it as well)
123
+ * normalizing (or sometimes called 'canonicalizing') the remaining JSON-LD document
124
+ * verifying the signature value with the public key (using RSA or Ed25519)
125
+
126
+ The ruby-jsonld-signatures gem relies on other gems to perform signing
127
+ and verifying including:
128
+
129
+ * [json-ld](https://github.com/ruby-rdf/json-ld)
130
+ * [rdf-normalize](https://github.com/ruby-rdf/rdf-normalize)
131
+ * [ed25519](https://github.com/crypto-rb/ed25519)
132
+
133
+ NOTE: additional keys that are NOT in the context vocabularies will
134
+ NOT be part of the normalization process. Thus, the following JSON-LD
135
+ document is equalivalent to the blocks shown above:
136
+
137
+ ```json
138
+ {
139
+ "@context": [ "https://w3id.org/credentials/v1","https://w3id.org/security/v1"],
140
+ "type" : [ "Credential" ],
141
+ "claim" : {
142
+ "id" : "did:v1:test:nym:JApJf12r82Pe6PBJ3gJAAwo8F7uDnae6B4ab9EFQ7XXk",
143
+ "publicKey" : "did:v1:test:nym:JApJf12r82Pe6PBJ3gJAAwo8F7uDnae6B4ab9EFQ7XXk#authn-key-1"
144
+ },
145
+ "foo" : "bar",
146
+ "issuer" : "did:v1:test:nym:JApJf12r82Pe6PBJ3gJAAwo8F7uDnae6B4ab9EFQ7XXk",
147
+ "issued" : "2018-03-15T00:00:00Z"
148
+ }
149
+ ```
150
+
151
+ The key "foo" is not found in either the credentials or security
152
+ vocabularies (in the @context) and therefore *not* included in the
153
+ normalized content. But the following document is not equivalent (the
154
+ key "nonce" *is* part of both the credentials and security
155
+ vocabularies - but it just has to be in one of them):
156
+
157
+ ```json
158
+ {
159
+ "@context": [ "https://w3id.org/credentials/v1","https://w3id.org/security/v1"],
160
+ "type" : [ "Credential" ],
161
+ "claim" : {
162
+ "id" : "did:v1:test:nym:JApJf12r82Pe6PBJ3gJAAwo8F7uDnae6B4ab9EFQ7XXk",
163
+ "publicKey" : "did:v1:test:nym:JApJf12r82Pe6PBJ3gJAAwo8F7uDnae6B4ab9EFQ7XXk#authn-key-1"
164
+ },
165
+ "nonce" : "thisisjustarandomstring",
166
+ "issuer" : "did:v1:test:nym:JApJf12r82Pe6PBJ3gJAAwo8F7uDnae6B4ab9EFQ7XXk",
167
+ "issued" : "2018-03-15T00:00:00Z"
168
+ }
169
+ ```
170
+
171
+ By the way, here is the normalized (or "canonicalized") content for
172
+ all blocks above except the one with the "nonce" key-value pair added:
173
+
174
+ ```json
175
+ <did:v1:test:nym:JApJf12r82Pe6PBJ3gJAAwo8F7uDnae6B4ab9EFQ7XXk> <https://w3id.org/security#publicKey> <did:v1:test:nym:JApJf12r82Pe6PBJ3gJAAwo8F7uDnae6B4ab9EFQ7XXk#authn-key-1> .
176
+ _:c14n0 <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> <https://w3id.org/credentials#Credential> .
177
+ _:c14n0 <https://w3id.org/credentials#claim> <did:v1:test:nym:JApJf12r82Pe6PBJ3gJAAwo8F7uDnae6B4ab9EFQ7XXk> .
178
+ _:c14n0 <https://w3id.org/credentials#issued> "2018-03-15T00:00:00Z"^^<http://www.w3.org/2001/XMLSchema#dateTime> .
179
+ _:c14n0 <https://w3id.org/credentials#issuer> <did:v1:test:nym:JApJf12r82Pe6PBJ3gJAAwo8F7uDnae6B4ab9EFQ7XXk> .
180
+ ```
181
+
182
+ Tests
183
+ -----
184
+
185
+ * Sign a basic string
186
+ * Sign a basic normalized (i.e., "canonicalized") document
187
+ * Sign a basic JSON-LD document
188
+ * Signatures of a second document that contains a non-vocabulary element are equivalent
189
+ * Signatures of a second document that contains a vocabulary element are NOT equivalent
190
+ * Signatures of a second document in different order are equivalent
191
+ * Verify signature of a signed JSON-LD document
192
+ * Detect when signature of a signed JSON-LD document is invalid
193
+
194
+ Todo
195
+ ----
196
+
197
+ * The gem currently uses the [ed25519](https://github.com/crypto-rb/ed25519) gem, but I have tested the
198
+ [rbnacl](https://github.com/crypto-rb/rbnacl) gem and it works. I just need to provide an option hook.
199
+
data/VERSION ADDED
@@ -0,0 +1 @@
1
+ 0.0.10
@@ -0,0 +1,50 @@
1
+ module JSON
2
+ module LD
3
+ module SIGNATURE
4
+
5
+ require 'base64'
6
+ require 'json/ld'
7
+ require 'rdf/normalize'
8
+ require 'json/ld/signature'
9
+ require 'json/ld/signature/ed25519Signer'
10
+ require 'json/ld/signature/ed25519Verifier'
11
+ require 'json/ld/signature/rsaSigner'
12
+ require 'json/ld/signature/rsaVerifier'
13
+
14
+ autoload :Ed25519Singer, 'json/ld/signature/ed25519Singer'
15
+ autoload :Ed25519Verifier, 'json/ld/signature/ed25519Verifier'
16
+ autoload :RsaSinger, 'json/ld/signature/rsaSinger'
17
+ autoload :RsaVerifier, 'json/ld/signature/rsaVerifier'
18
+
19
+ def generateNormalizedGraph(jsonLDDoc, opts)
20
+ jsonLDDoc.delete 'signature'
21
+
22
+ graph = RDF::Graph.new << JSON::LD::API.toRdf(jsonLDDoc)
23
+ # TODO: Parameterize the normalization
24
+ normalized = graph.dump(:normalize)
25
+
26
+ # digestdoc = ''
27
+ # digestdoc << opts['nonce'] unless opts['nonce'].nil?
28
+ # digestdoc << opts['created']
29
+ # digestdoc << normalized
30
+ # digestdoc << '@' + opts['domain'] unless opts['domain'].nil?
31
+ # digestdoc
32
+
33
+ normalized
34
+ end
35
+
36
+ module_function :generateNormalizedGraph
37
+
38
+ SECURITY_CONTEXT_URL = 'https://w3id.org/security/v1'
39
+
40
+ class JsonLdSignatureError < JsonLdError
41
+ class InvalidJsonLdDocument < JsonLdSignatureError; @code = "invalid JSON-LD document"; end
42
+ class MissingCreator < JsonLdSignatureError; @code = "missing signature creator"; end
43
+ class MissingKey < JsonLdSignatureError; @code = "missing private PEM formatted string"; end
44
+ class InvalidKeyType < JsonLdSignatureError; @code = "invalid PEM key"; end
45
+ class WrongKeyType < JsonLdSignatureError; @code = "signing requires a private key"; end
46
+ class UnreachableKey < JsonLdSignatureError; @code = "unable to retrieve public key"; end
47
+ end
48
+ end
49
+ end
50
+ end
@@ -0,0 +1,98 @@
1
+ module JSON
2
+ module LD
3
+ module SIGNATURE
4
+
5
+ class Ed25519Signer
6
+
7
+ attr_writer :pub
8
+ attr_writer :priv
9
+
10
+ def pub
11
+ @pub
12
+ end
13
+
14
+ def priv
15
+ @priv
16
+ end
17
+
18
+ def sign(input, options = {} )
19
+
20
+ # We require a creator to identify the signing key
21
+
22
+ if options['creator'].nil?
23
+ raise JsonLdSignatureError::MissingCreator, "the creator of the signature must be identified"
24
+ end
25
+
26
+ creator = options['creator']
27
+
28
+ # TODO: Validate the resolvability of the URL?
29
+
30
+ # We require a privateKeyPem in the options hash
31
+ # if options['privateKey'].nil?
32
+ # raise JsonLdSignatureError::MissingKey, "options parameter must include privateKey"
33
+ # end
34
+
35
+ # The privateKeyPem can be either a String or a parsed RSA key
36
+ # privateKey = options['privateKey']
37
+ privateKey = priv
38
+
39
+ # unless privateKey.private?
40
+ # raise JsonLdSignatureError::WrongKeyType, "submitted key is a public key"
41
+ # end
42
+
43
+ # Check the input, it should either be a String or a parsed JSON object
44
+
45
+ jsonld = case input
46
+ when String then
47
+ begin
48
+ JSON.parse(input)
49
+ rescue JSON::ParserError => e
50
+ raise JsonLdSignatureError::InvalidJsonLdDocument, e.message
51
+ end
52
+ when Hash then input
53
+ else
54
+ raise JsonLdSignatureError::InvalidJsonLdDocument
55
+ end
56
+
57
+ jsonld.delete 'signature'
58
+ # created = Time.now.iso8601
59
+ created = "2018-03-15T00:00:00Z"
60
+ # nonce = options['nonce']
61
+ # nonce = "3699b48f-a194-4415-8da3-b76269f63746"
62
+ nonce = nil
63
+ # domain = options['domain']
64
+ domain = nil
65
+
66
+ normOpts = {
67
+ 'nonce' => nonce,
68
+ 'domain' => options['domain'],
69
+ 'created' => created,
70
+ 'creator' => creator
71
+ }
72
+
73
+ normalizedGraph = JSON::LD::SIGNATURE::generateNormalizedGraph jsonld, normOpts
74
+ # puts normalizedGraph
75
+ signature = privateKey.sign normalizedGraph
76
+
77
+ enc = Base64.strict_encode64(signature)
78
+
79
+ # "@context" : "https://w3id.org/security/v1",
80
+
81
+ sigobj = JSON.parse %({
82
+ "type" : "Ed25519Signature2018",
83
+ "creator" : "#{creator}",
84
+ "created" : "#{created}",
85
+ "signatureValue" : "#{enc}"
86
+ })
87
+
88
+ sigobj['domain'] = domain unless options['domain'].nil?
89
+ sigobj['nonce'] = nonce unless nonce.nil?
90
+
91
+ jsonld['signature'] = sigobj
92
+ jsonld.to_json
93
+ end
94
+ end
95
+ end
96
+ end
97
+ end
98
+
@@ -0,0 +1,68 @@
1
+ module JSON
2
+ module LD
3
+ module SIGNATURE
4
+
5
+ class Ed25519Verifier
6
+
7
+ attr_writer :pub
8
+ attr_writer :priv
9
+
10
+ def pub
11
+ @pub
12
+ end
13
+
14
+ def priv
15
+ @priv
16
+ end
17
+
18
+ def verify(input, options = {})
19
+
20
+ # We require a publicKeyPem in the options hash
21
+ # if options['publicKey'].nil?
22
+ # raise JsonLdSignatureError::MissingKey, "options parameter must include publicKey"
23
+ # end
24
+
25
+ # The publicKeyPem can be either a String or a parsed RSA key
26
+ # publicKey = options['publicKey']
27
+ publicKey = pub
28
+
29
+ # Check the input, it should either be a String or a parsed JSON object
30
+
31
+ jsonld = case input
32
+ when String then
33
+ begin
34
+ JSON.parse(input)
35
+ rescue JSON::ParserError => e
36
+ raise JsonLdSignatureError::InvalidJsonLdDocument, e.message
37
+ end
38
+ when Hash then input
39
+ else
40
+ raise JsonLdSignatureError::InvalidJsonLdDocument
41
+ end
42
+
43
+ signature = jsonld['signature']
44
+
45
+ created = signature['created']
46
+ creator = signature['creator']
47
+ signatureValue = signature['signatureValue']
48
+ domain = signature['domain']
49
+ nonce = signature['nonce']
50
+
51
+ uri = URI(creator)
52
+
53
+ normOpts = {
54
+ 'nonce' => nonce,
55
+ 'domain' => domain,
56
+ 'created' => created,
57
+ 'creator' => creator
58
+ }
59
+
60
+ normalizedGraph = JSON::LD::SIGNATURE::generateNormalizedGraph jsonld, normOpts
61
+
62
+ publicKey.verify Base64.decode64(signatureValue), normalizedGraph
63
+ end
64
+ end
65
+ end
66
+ end
67
+ end
68
+
@@ -0,0 +1,100 @@
1
+ module JSON
2
+ module LD
3
+ module SIGNATURE
4
+
5
+ class RsaSigner
6
+
7
+ attr_writer :pub
8
+ attr_writer :priv
9
+
10
+ def pub
11
+ @pub
12
+ end
13
+
14
+ def priv
15
+ @priv
16
+ end
17
+
18
+ def sign(input, options = {} )
19
+
20
+ # We require a creator to identify the signing key
21
+
22
+ if options['creator'].nil?
23
+ raise JsonLdSignatureError::MissingCreator, "the creator of the signature must be identified"
24
+ end
25
+
26
+ creator = options['creator']
27
+
28
+ # TODO: Validate the resolvability of the URL?
29
+
30
+ # We require a privateKeyPem in the options hash
31
+ # if options['privateKeyPem'].nil?
32
+ # raise JsonLdSignatureError::MissingKey, "options parameter must include privateKeyPem"
33
+ # end
34
+
35
+ # The privateKeyPem can be either a String or a parsed RSA key
36
+ # privateKey = case options['privateKeyPem']
37
+ # when String then OpenSSL::PKey::RSA.new options['privateKeyPem']
38
+ # when OpenSSL::PKey::RSA then options['privateKeyPem']
39
+ # else
40
+ # raise JsonLdSignatureError::InvalidKeyType, "key must be RSA Key or PEM String"
41
+ # end
42
+ privateKey = @priv
43
+
44
+ unless privateKey.private?
45
+ raise JsonLdSignatureError::WrongKeyType, "submitted key is a public key"
46
+ end
47
+
48
+ # Check the input, it should either be a String or a parsed JSON object
49
+
50
+ jsonld = case input
51
+ when String then
52
+ begin
53
+ JSON.parse(input)
54
+ rescue JSON::ParserError => e
55
+ raise JsonLdSignatureError::InvalidJsonLdDocument, e.message
56
+ end
57
+ when Hash then input
58
+ else
59
+ raise JsonLdSignatureError::InvalidJsonLdDocument
60
+ end
61
+
62
+ jsonld.delete 'signature'
63
+ # created = Time.now.iso8601
64
+ created = "2018-03-15T00:00:00Z"
65
+ nonce = options['nonce']
66
+ domain = options['domain']
67
+
68
+ normOpts = {
69
+ 'nonce' => nonce,
70
+ 'domain' => options['domain'],
71
+ 'created' => created,
72
+ 'creator' => creator
73
+ }
74
+
75
+ normalizedGraph = JSON::LD::SIGNATURE::generateNormalizedGraph jsonld, normOpts
76
+
77
+ digest = OpenSSL::Digest::SHA256.new
78
+ signature = privateKey.sign digest, normalizedGraph
79
+ enc = Base64.strict_encode64(signature)
80
+
81
+ # "@context" : "https://w3id.org/security/v1",
82
+
83
+ sigobj = JSON.parse %({
84
+ "type" : "RsaSignature2017",
85
+ "creator" : "#{creator}",
86
+ "created" : "#{created}",
87
+ "signatureValue" : "#{enc}"
88
+ })
89
+
90
+ sigobj['domain'] = domain unless options['domain'].nil?
91
+ sigobj['nonce'] = nonce unless nonce.nil?
92
+
93
+ jsonld['signature'] = sigobj
94
+ jsonld.to_json
95
+ end
96
+ end
97
+ end
98
+ end
99
+ end
100
+
@@ -0,0 +1,83 @@
1
+ module JSON
2
+ module LD
3
+ module SIGNATURE
4
+
5
+ class RsaVerifier
6
+
7
+ attr_writer :pub
8
+ attr_writer :priv
9
+
10
+ def pub
11
+ @pub
12
+ end
13
+
14
+ def priv
15
+ @priv
16
+ end
17
+
18
+ def verify(input, options = {})
19
+
20
+ # We require a publicKeyPem in the options hash
21
+ # if options['publicKeyPem'].nil?
22
+ # raise JsonLdSignatureError::MissingKey, "options parameter must include publicKeyPem"
23
+ # end
24
+
25
+ # The publicKeyPem can be either a String or a parsed RSA key
26
+ # publicKey = case options['publicKeyPem']
27
+ # when String then OpenSSL::PKey::RSA.new options['publicKeyPem']
28
+ # when OpenSSL::PKey::RSA then options['publicKeyPem']
29
+ # else
30
+ # raise JsonLdSignatureError::InvalidKeyType, "key must be RSA Key or PEM String"
31
+ # end
32
+ publicKey = @pub
33
+
34
+ # Check the input, it should either be a String or a parsed JSON object
35
+
36
+ jsonld = case input
37
+ when String then
38
+ begin
39
+ JSON.parse(input)
40
+ rescue JSON::ParserError => e
41
+ raise JsonLdSignatureError::InvalidJsonLdDocument, e.message
42
+ end
43
+ when Hash then input
44
+ else
45
+ raise JsonLdSignatureError::InvalidJsonLdDocument
46
+ end
47
+
48
+ signature = jsonld['signature']
49
+
50
+ created = signature['created']
51
+ creator = signature['creator']
52
+ signatureValue = signature['signatureValue']
53
+ domain = signature['domain']
54
+ nonce = signature['nonce']
55
+
56
+ uri = URI(creator)
57
+ # response = Net::HTTP.get_response(uri)
58
+
59
+ # case response.code
60
+ # when "200"
61
+ # publicKey = OpenSSL::PKey::RSA.new response.body
62
+ # else
63
+ # raise JsonLdSignatureError::UnreachableKey,
64
+ # "Key #{creator} could not be retrieved. Error: #{response.code}, #{response.message}"
65
+ # end
66
+
67
+ normOpts = {
68
+ 'nonce' => nonce,
69
+ 'domain' => domain,
70
+ 'created' => created,
71
+ 'creator' => creator
72
+ }
73
+
74
+ normalizedGraph = JSON::LD::SIGNATURE::generateNormalizedGraph jsonld, normOpts
75
+
76
+ digest = OpenSSL::Digest::SHA256.new
77
+ publicKey.verify digest, Base64.decode64(signatureValue), normalizedGraph
78
+ end
79
+ end
80
+ end
81
+ end
82
+ end
83
+
metadata ADDED
@@ -0,0 +1,186 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: ruby-jsonld-signatures
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.10
5
+ platform: ruby
6
+ authors:
7
+ - Brian Sletten
8
+ - John Callahan
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2018-09-27 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: rdf
16
+ requirement: !ruby/object:Gem::Requirement
17
+ requirements:
18
+ - - "~>"
19
+ - !ruby/object:Gem::Version
20
+ version: 3.0.4
21
+ type: :runtime
22
+ prerelease: false
23
+ version_requirements: !ruby/object:Gem::Requirement
24
+ requirements:
25
+ - - "~>"
26
+ - !ruby/object:Gem::Version
27
+ version: 3.0.4
28
+ - !ruby/object:Gem::Dependency
29
+ name: rdf-normalize
30
+ requirement: !ruby/object:Gem::Requirement
31
+ requirements:
32
+ - - ">="
33
+ - !ruby/object:Gem::Version
34
+ version: '0'
35
+ type: :runtime
36
+ prerelease: false
37
+ version_requirements: !ruby/object:Gem::Requirement
38
+ requirements:
39
+ - - ">="
40
+ - !ruby/object:Gem::Version
41
+ version: '0'
42
+ - !ruby/object:Gem::Dependency
43
+ name: rdf-turtle
44
+ requirement: !ruby/object:Gem::Requirement
45
+ requirements:
46
+ - - ">="
47
+ - !ruby/object:Gem::Version
48
+ version: '0'
49
+ type: :runtime
50
+ prerelease: false
51
+ version_requirements: !ruby/object:Gem::Requirement
52
+ requirements:
53
+ - - ">="
54
+ - !ruby/object:Gem::Version
55
+ version: '0'
56
+ - !ruby/object:Gem::Dependency
57
+ name: rdf-spec
58
+ requirement: !ruby/object:Gem::Requirement
59
+ requirements:
60
+ - - ">="
61
+ - !ruby/object:Gem::Version
62
+ version: '0'
63
+ type: :development
64
+ prerelease: false
65
+ version_requirements: !ruby/object:Gem::Requirement
66
+ requirements:
67
+ - - ">="
68
+ - !ruby/object:Gem::Version
69
+ version: '0'
70
+ - !ruby/object:Gem::Dependency
71
+ name: open-uri-cached
72
+ requirement: !ruby/object:Gem::Requirement
73
+ requirements:
74
+ - - "~>"
75
+ - !ruby/object:Gem::Version
76
+ version: '0.0'
77
+ - - ">="
78
+ - !ruby/object:Gem::Version
79
+ version: 0.0.5
80
+ type: :development
81
+ prerelease: false
82
+ version_requirements: !ruby/object:Gem::Requirement
83
+ requirements:
84
+ - - "~>"
85
+ - !ruby/object:Gem::Version
86
+ version: '0.0'
87
+ - - ">="
88
+ - !ruby/object:Gem::Version
89
+ version: 0.0.5
90
+ - !ruby/object:Gem::Dependency
91
+ name: rspec
92
+ requirement: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - "~>"
95
+ - !ruby/object:Gem::Version
96
+ version: '3.2'
97
+ type: :development
98
+ prerelease: false
99
+ version_requirements: !ruby/object:Gem::Requirement
100
+ requirements:
101
+ - - "~>"
102
+ - !ruby/object:Gem::Version
103
+ version: '3.2'
104
+ - !ruby/object:Gem::Dependency
105
+ name: webmock
106
+ requirement: !ruby/object:Gem::Requirement
107
+ requirements:
108
+ - - "~>"
109
+ - !ruby/object:Gem::Version
110
+ version: 2.3.2
111
+ type: :development
112
+ prerelease: false
113
+ version_requirements: !ruby/object:Gem::Requirement
114
+ requirements:
115
+ - - "~>"
116
+ - !ruby/object:Gem::Version
117
+ version: 2.3.2
118
+ - !ruby/object:Gem::Dependency
119
+ name: json-ld
120
+ requirement: !ruby/object:Gem::Requirement
121
+ requirements:
122
+ - - "~>"
123
+ - !ruby/object:Gem::Version
124
+ version: 3.0.2
125
+ type: :development
126
+ prerelease: false
127
+ version_requirements: !ruby/object:Gem::Requirement
128
+ requirements:
129
+ - - "~>"
130
+ - !ruby/object:Gem::Version
131
+ version: 3.0.2
132
+ - !ruby/object:Gem::Dependency
133
+ name: yard
134
+ requirement: !ruby/object:Gem::Requirement
135
+ requirements:
136
+ - - "~>"
137
+ - !ruby/object:Gem::Version
138
+ version: '0.8'
139
+ type: :development
140
+ prerelease: false
141
+ version_requirements: !ruby/object:Gem::Requirement
142
+ requirements:
143
+ - - "~>"
144
+ - !ruby/object:Gem::Version
145
+ version: '0.8'
146
+ description: RDF::JSON::LD:Signature is an implementation of the JSON-LD Signature
147
+ specification for the RDF.rb library suite.
148
+ email: public-rdf-ruby@w3.org
149
+ executables: []
150
+ extensions: []
151
+ extra_rdoc_files: []
152
+ files:
153
+ - AUTHORS
154
+ - LICENSE
155
+ - README.md
156
+ - VERSION
157
+ - lib/json/ld/signature.rb
158
+ - lib/json/ld/signature/ed25519Signer.rb
159
+ - lib/json/ld/signature/ed25519Verifier.rb
160
+ - lib/json/ld/signature/rsaSigner.rb
161
+ - lib/json/ld/signature/rsaVerifier.rb
162
+ homepage: http://github.com/bsletten/rdf-jsonld-signature
163
+ licenses:
164
+ - MIT
165
+ metadata: {}
166
+ post_install_message:
167
+ rdoc_options: []
168
+ require_paths:
169
+ - lib
170
+ required_ruby_version: !ruby/object:Gem::Requirement
171
+ requirements:
172
+ - - ">="
173
+ - !ruby/object:Gem::Version
174
+ version: 1.9.2
175
+ required_rubygems_version: !ruby/object:Gem::Requirement
176
+ requirements:
177
+ - - ">="
178
+ - !ruby/object:Gem::Version
179
+ version: '0'
180
+ requirements: []
181
+ rubyforge_project: rdf-normalize
182
+ rubygems_version: 2.7.7
183
+ signing_key:
184
+ specification_version: 4
185
+ summary: JSON-LD Signature implementation for Ruby.
186
+ test_files: []