oydid 0.5.6 → 0.6.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
data/lib/oydid.rb CHANGED
@@ -1,14 +1,20 @@
1
1
  # -*- encoding: utf-8 -*-
2
2
  # frozen_string_literal: true
3
3
 
4
- require 'simple_dag'
5
4
  require 'jwt'
5
+ require 'jwt/eddsa'
6
+ require 'rdf'
7
+ require 'rdf/normalize'
8
+ require 'json'
9
+ require 'json/ld'
6
10
  require 'rbnacl'
7
11
  require 'ed25519'
12
+ require 'openssl'
8
13
  require 'httparty'
9
14
  require 'multibases'
10
- require 'multihashes'
11
15
  require 'multicodecs'
16
+ require 'simple_dag'
17
+ require 'securerandom'
12
18
  require 'json/canonicalization'
13
19
  require 'oydid/basic'
14
20
  require 'oydid/log'
@@ -24,6 +30,8 @@ class Oydid
24
30
  DEFAULT_ENCODING = "base58btc"
25
31
  SUPPORTED_ENCODINGS = ["base16", "base32", "base58btc", "base64"]
26
32
  LOG_HASH_OPTIONS = {:digest => "sha2-256", :encode => "base58btc"}
33
+ ED25519_SECURITY_SUITE = "https://w3id.org/security/suites/ed25519-2020/v1"
34
+ JWS_SECURITY_SUITE = "https://w3id.org/security/suites/jws-2020/v1"
27
35
  DEFAULT_PUBLIC_RESOLVER = "https://dev.uniresolver.io/1.0/identifiers/"
28
36
 
29
37
  # full Multicodecs table: https://github.com/multiformats/multicodec/blob/master/table.csv
@@ -178,7 +186,8 @@ class Oydid
178
186
  if !content.nil?
179
187
  return [nil, nil, nil, "invalid payload"]
180
188
  end
181
- end
189
+ end
190
+
182
191
  did_old = nil
183
192
  log_old = nil
184
193
  prev_hash = []
@@ -190,22 +199,73 @@ class Oydid
190
199
  ts = options[:ts]
191
200
  end
192
201
 
193
- # key management
194
- tmp_did_hash = did.delete_prefix("did:oyd:") rescue ""
195
- tmp_did10 = tmp_did_hash[0,10] + "_private_key.enc" rescue ""
196
- privateKey, msg = getPrivateKey(options[:doc_enc], options[:doc_pwd], options[:doc_key], tmp_did10, options)
197
- if privateKey.nil?
198
- privateKey, msg = generate_private_key("", 'ed25519-priv', options)
202
+ options[:cmsm2] = false
203
+ if options[:cmsm]
204
+ if did_doc["key"].nil?
205
+ return [nil, nil, nil, "CMSM requires public key"]
206
+ end
207
+ cmsm_keys = did_doc["key"].split(':')
208
+ did_doc.delete("key")
209
+ if did_doc == {}
210
+ did_doc = nil
211
+ end
212
+ if cmsm_keys.count == 1
213
+ publicKey = cmsm_keys.first
214
+ revocationKey, msg = generate_private_key("", options[:key_type]+'-priv', options)
215
+ pubRevoKey = public_key(revocationKey, options).first
216
+ else
217
+ return [nil, nil, nil, "CMSM with multiple keys is not yet supported"]
218
+ end
219
+
220
+ # check if information for provided key already exists
221
+ payload, msg = check_cmsm(publicKey, options)
222
+ if !payload.nil? && !did_doc.nil? && !did_doc["opt"].nil?
223
+ if payload.is_a?(String)
224
+ payload = JSON.parse(payload) rescue nil
225
+ end
226
+ if payload.nil?
227
+ return [nil, nil, nil, "invalid persisted data in CMSM flow"]
228
+ end
229
+ did_doc = JSON.parse(did_doc.to_json)
230
+ if did_doc["opt"].nil?
231
+ if options[:sig].nil?
232
+ return [nil, nil, nil, "1missing signature in CMSM flow (sig)"]
233
+ end
234
+ l2_sig = options[:sig]
235
+ else
236
+ if did_doc["opt"]["sig"].nil?
237
+ return [nil, nil, nil, "2missing signature in CMSM flow (sig)"]
238
+ end
239
+ l2_sig = did_doc["opt"]["sig"]
240
+ end
241
+
242
+ options[:cmsm2] = true
243
+ privateKey = nil
244
+
245
+ revocationKey = payload["revocationKey"]
246
+ did_doc = payload["did_doc"]
247
+ did_key = payload["did_key"]
248
+ l2_doc = payload["l2_doc"]
249
+ r1 = payload["r1"]
250
+ end
251
+ else
252
+ # key management
253
+ tmp_did_hash = did.delete_prefix("did:oyd:") rescue ""
254
+ tmp_did10 = tmp_did_hash[0,10] + "_private_key.enc" rescue ""
255
+ privateKey, msg = getPrivateKey(options[:doc_enc], options[:doc_pwd], options[:doc_key], tmp_did10, options)
199
256
  if privateKey.nil?
200
- return [nil, nil, nil, "private document key not found"]
257
+ privateKey, msg = generate_private_key("", options[:key_type]+'-priv', options)
258
+ if privateKey.nil?
259
+ return [nil, nil, nil, "private document key not found"]
260
+ end
201
261
  end
202
- end
203
- tmp_did10 = tmp_did_hash[0,10] + "_revocation_key.enc" rescue ""
204
- revocationKey, msg = getPrivateKey(options[:rev_enc], options[:rev_pwd], options[:rev_key], tmp_did10, options)
205
- if revocationKey.nil?
206
- revocationKey, msg = generate_private_key("", 'ed25519-priv', options)
262
+ tmp_did10 = tmp_did_hash[0,10] + "_revocation_key.enc" rescue ""
263
+ revocationKey, msg = getPrivateKey(options[:rev_enc], options[:rev_pwd], options[:rev_key], tmp_did10, options)
207
264
  if revocationKey.nil?
208
- return [nil, nil, nil, "private revocation key not found"]
265
+ revocationKey, msg = generate_private_key("", options[:key_type]+'-priv', options)
266
+ if revocationKey.nil?
267
+ return [nil, nil, nil, "private revocation key not found"]
268
+ end
209
269
  end
210
270
  end
211
271
 
@@ -239,12 +299,13 @@ class Oydid
239
299
  log_old = did_info["log"]
240
300
 
241
301
  # check if provided old keys are native DID keys or delegates ==================
242
- tmp_old_did10 = did10_old + "_private_key.enc" rescue ""
243
- old_privateKey, msg = getPrivateKey(options[:old_doc_enc], options[:old_doc_pwd], options[:old_doc_key], tmp_old_did10, options)
244
- tmp_old_did10 = did10_old + "_revocation_key.enc" rescue ""
245
- old_revocationKey, msg = getPrivateKey(options[:old_rev_enc], options[:old_rev_pwd], options[:old_rev_key], tmp_did10, options)
302
+ tmp_old_doc_did10 = did10_old + "_private_key.enc" rescue ""
303
+ old_privateKey, msg = getPrivateKey(options[:old_doc_enc], options[:old_doc_pwd], options[:old_doc_key], tmp_old_doc_did10, options)
304
+ tmp_old_rev_did10 = did10_old + "_revocation_key.enc" rescue ""
305
+ old_revocationKey, msg = getPrivateKey(options[:old_rev_enc], options[:old_rev_pwd], options[:old_rev_key], tmp_old_rev_did10, options)
246
306
  old_publicDocKey = public_key(old_privateKey, {}).first
247
307
  old_publicRevKey = public_key(old_revocationKey, {}).first
308
+
248
309
  old_did_key = old_publicDocKey + ":" + old_publicRevKey
249
310
 
250
311
  # compare old keys with existing DID Document & generate revocation record
@@ -299,49 +360,79 @@ class Oydid
299
360
  ]
300
361
  prev_hash = [multi_hash(canonical(revoc_log), LOG_HASH_OPTIONS).first]
301
362
  end
302
- publicKey = public_key(privateKey, options).first
303
- pubRevoKey = public_key(revocationKey, options).first
304
- did_key = publicKey + ":" + pubRevoKey
363
+ if !options[:cmsm2]
364
+ if !options[:cmsm]
365
+ publicKey = public_key(privateKey, options).first
366
+ pubRevoKey = public_key(revocationKey, options).first
367
+ end
368
+ did_key = publicKey + ":" + pubRevoKey
305
369
 
306
- if options[:x25519_keyAgreement]
307
- if did_doc.nil?
308
- did_doc = {}
370
+ if options[:keyAgreement]
371
+ if did_doc.nil?
372
+ did_doc = {}
373
+ end
374
+ did_doc[:keyAgreement] = ["#key-doc"]
375
+ did_doc = did_doc.transform_keys(&:to_s)
309
376
  end
310
- did_doc[:keyAgreement] = [{
311
- "id": "#key-doc-x25519",
312
- "type": "X25519KeyAgreementKey2019",
313
- "publicKeyMultibase": public_key(privateKey, options, 'x25519-pub').first
314
- }]
315
- did_doc = did_doc.transform_keys(&:to_s)
316
- end
317
- if options[:authentication]
318
- if did_doc.nil?
319
- did_doc = {}
377
+ if options[:x25519_keyAgreement]
378
+ if did_doc.nil?
379
+ did_doc = {}
380
+ end
381
+ did_doc[:keyAgreement] = [{
382
+ "id": "#key-doc-x25519",
383
+ "type": "X25519KeyAgreementKey2019",
384
+ "publicKeyMultibase": public_key(privateKey, options, 'x25519-pub').first
385
+ }]
386
+ did_doc = did_doc.transform_keys(&:to_s)
387
+ end
388
+ if options[:authentication]
389
+ if did_doc.nil?
390
+ did_doc = {}
391
+ end
392
+ did_doc[:authentication] = ["#key-doc"]
393
+ did_doc = did_doc.transform_keys(&:to_s)
320
394
  end
321
- did_doc[:authentication] = [{
322
- "id": "#key-doc"
323
- }]
324
- did_doc = did_doc.transform_keys(&:to_s)
325
- end
326
395
 
327
- # build new revocation document
328
- subDid = {"doc": did_doc, "key": did_key}.to_json
329
- retVal = multi_hash(canonical(subDid), LOG_HASH_OPTIONS)
330
- if retVal.first.nil?
331
- return [nil, nil, nil, retVal.last]
332
- end
333
- subDidHash = retVal.first
334
- signedSubDidHash = sign(subDidHash, revocationKey, options).first
335
- r1 = { "ts": ts,
336
- "op": 1, # REVOKE
337
- "doc": subDidHash,
338
- "sig": signedSubDidHash }.transform_keys(&:to_s)
396
+ # build new revocation document
397
+ subDid = {"doc": did_doc, "key": did_key}.to_json
398
+ retVal = multi_hash(canonical(subDid), LOG_HASH_OPTIONS)
399
+ if retVal.first.nil?
400
+ return [nil, nil, nil, retVal.last]
401
+ end
402
+ subDidHash = retVal.first
403
+ signedSubDidHash = sign(subDidHash, revocationKey, LOG_HASH_OPTIONS).first
404
+ r1 = { "ts": ts,
405
+ "op": 1, # REVOKE
406
+ "doc": subDidHash,
407
+ "sig": signedSubDidHash }.transform_keys(&:to_s)
408
+
409
+ # build termination log entry
410
+ l2_doc = multi_hash(canonical(r1), LOG_HASH_OPTIONS).first
411
+ if !doc_location.nil?
412
+ l2_doc += LOCATION_PREFIX + doc_location.to_s
413
+ end
339
414
 
340
- # build termination log entry
341
- l2_doc = multi_hash(canonical(r1), LOG_HASH_OPTIONS).first
342
- if !doc_location.nil?
343
- l2_doc += LOCATION_PREFIX + doc_location.to_s
415
+ if options[:cmsm]
416
+ # persist data
417
+ payload = {
418
+ revocationKey: revocationKey,
419
+ did_doc: did_doc,
420
+ did_key: did_key,
421
+ l2_doc: l2_doc,
422
+ r1: r1
423
+ }
424
+ success, msg = persist_cmsm(publicKey, payload, options)
425
+
426
+ cmsm_doc = {
427
+ cmsm: true,
428
+ pk: publicKey,
429
+ sign: l2_doc
430
+ }
431
+ return [cmsm_doc, nil, r1, "cmsm"]
432
+ end
433
+ l2_sig = sign(l2_doc, privateKey, options).first
344
434
  end
435
+
345
436
  if options[:confirm_logs].nil?
346
437
  previous_array = []
347
438
  else
@@ -350,7 +441,7 @@ class Oydid
350
441
  l2 = { "ts": ts,
351
442
  "op": 0, # TERMINATE
352
443
  "doc": l2_doc,
353
- "sig": sign(l2_doc, privateKey, options).first,
444
+ "sig": l2_sig,
354
445
  "previous": previous_array }.transform_keys(&:to_s)
355
446
 
356
447
  # build actual DID document
@@ -387,11 +478,15 @@ class Oydid
387
478
 
388
479
  # build creation log entry
389
480
  log_revoke_encrypted_array = nil
481
+ l1_sig = nil
390
482
  if operation_mode == 3 # UPDATE
483
+ if !options[:cmsm]
484
+ l1_sig = sign(l1_doc, old_privateKey, options).first
485
+ end
391
486
  l1 = { "ts": ts,
392
487
  "op": operation_mode, # UPDATE
393
488
  "doc": l1_doc,
394
- "sig": sign(l1_doc, old_privateKey, options).first,
489
+ "sig": l1_sig,
395
490
  "previous": prev_hash }.transform_keys(&:to_s)
396
491
  options[:confirm_logs].each do |el|
397
492
  # read each log entry to check if it is a revocation delegation
@@ -407,10 +502,13 @@ class Oydid
407
502
  end
408
503
  end unless options[:confirm_logs].nil?
409
504
  else
505
+ if !options[:cmsm]
506
+ l1_sig = sign(l1_doc, privateKey, options).first
507
+ end
410
508
  l1 = { "ts": ts,
411
509
  "op": operation_mode, # CREATE
412
510
  "doc": l1_doc,
413
- "sig": sign(l1_doc, privateKey, options).first,
511
+ "sig": l1_sig,
414
512
  "previous": prev_hash }.transform_keys(&:to_s)
415
513
  end
416
514
 
@@ -480,13 +578,69 @@ class Oydid
480
578
  write_private_storage(didDocument.to_json, did10 + ".doc")
481
579
  write_private_storage(did, did10 + ".did")
482
580
  end
581
+
483
582
  return [true, ""]
484
583
 
485
584
  end
486
585
 
586
+ def self.persist_cmsm(pubkey, payload, options)
587
+ doc_location = options[:doc_location]
588
+ if doc_location.to_s == ""
589
+ doc_location = DEFAULT_LOCATION
590
+ end
591
+ doc_location = doc_location.sub("%3A%2F%2F","://").sub("%3A", ":")
592
+
593
+ my_body = {
594
+ pubkey: pubkey,
595
+ payload: payload.to_json
596
+ }
597
+ case doc_location.to_s
598
+ when /^http/
599
+ persist_url = doc_location.to_s + "/cmsm"
600
+ retVal = HTTParty.post(persist_url,
601
+ headers: { 'Content-Type' => 'application/json' },
602
+ body: my_body.to_json )
603
+ if retVal.code != 200
604
+ err_msg = retVal.parsed_response("error").to_s rescue "invalid response from " + doc_location.to_s + "/cmsm"
605
+ return [false, err_msg]
606
+ end
607
+ else
608
+ return [nil, "location not supported for persisting data in cmsm-flow"]
609
+ end
610
+ return [true, ""]
611
+
612
+ end
613
+
614
+ def self.check_cmsm(pubkey, options)
615
+ doc_location = options[:doc_location]
616
+ if doc_location.to_s == ""
617
+ doc_location = DEFAULT_LOCATION
618
+ end
619
+ doc_location = doc_location.sub("%3A%2F%2F","://").sub("%3A", ":")
620
+
621
+ case doc_location.to_s
622
+ when /^http/
623
+ retVal = HTTParty.get(doc_location + "/cmsm/" + pubkey)
624
+ if retVal.code != 200
625
+ msg = retVal.parsed_response["error"].to_s rescue ""
626
+ if msg.to_s == ""
627
+ msg = "invalid response from " + doc_location.to_s + "/cmsm/" + pubkey.to_s
628
+ end
629
+ return [nil, msg]
630
+ end
631
+ return [retVal.parsed_response.transform_keys(&:to_s), ""]
632
+ else
633
+ return [nil, "location not supported for querying data in cmsm-flow"]
634
+ end
635
+ return [payload, ""]
636
+ end
637
+
487
638
  def self.write(content, did, mode, options)
488
639
  did_doc, did_key, did_log, msg = generate_base(content, did, mode, options)
489
640
  if msg != ""
641
+ if msg == "cmsm"
642
+ return [did_doc, 'cmsm']
643
+ end
490
644
  return [nil, msg]
491
645
  end
492
646
  did = did_doc[:did]
@@ -517,6 +671,7 @@ class Oydid
517
671
  doc_location = DEFAULT_LOCATION
518
672
  end
519
673
  end
674
+
520
675
  case doc_location.to_s
521
676
  when /^http/
522
677
  logs = [revoc_log, l1, l2, r1_encrypted].flatten.compact
@@ -526,6 +681,7 @@ class Oydid
526
681
  write_private_storage([log_old, revoc_log, l1, l2].flatten.compact.to_json, did10_old + ".log")
527
682
  end
528
683
  end
684
+
529
685
  success, msg = publish(did, didDocument, logs, options)
530
686
 
531
687
  if success
@@ -534,7 +690,7 @@ class Oydid
534
690
  "did" => did.clone,
535
691
  "doc" => didDocument.clone
536
692
  }
537
- doc_w3c = Oydid.w3c(w3c_input, options)
693
+ doc_w3c = w3c(w3c_input, options)
538
694
  didDocument = didDocumentBackup
539
695
  retVal = {
540
696
  "did" => did,
@@ -667,15 +823,16 @@ class Oydid
667
823
  did10_old = did10.dup
668
824
  log_old = did_info["log"]
669
825
 
826
+ msg = ""
670
827
  if options[:old_doc_key].nil?
671
828
  if options[:old_doc_enc].nil?
672
829
  if options[:old_doc_pwd].nil?
673
830
  privateKey_old = read_private_storage(did10_old + "_private_key.enc")
674
831
  else
675
- privateKey_old, msg = generate_private_key(options[:old_doc_pwd].to_s, 'ed25519-priv', options)
832
+ privateKey_old, msg = generate_private_key(options[:old_doc_pwd].to_s, options[:key_type]+'-priv', options)
676
833
  end
677
834
  else
678
- privateKey_old, msg = decode_private_key(options[:old_doc_enc].to_s, options)
835
+ privateKey_old = options[:old_doc_enc].to_s
679
836
  end
680
837
  else
681
838
  privateKey_old, msg = read_private_key(options[:old_doc_key].to_s, options)
@@ -688,10 +845,10 @@ class Oydid
688
845
  if options[:old_rev_pwd].nil?
689
846
  revocationKey_old = read_private_storage(did10_old + "_revocation_key.enc")
690
847
  else
691
- revocationKey_old, msg = generate_private_key(options[:old_rev_pwd].to_s, 'ed25519-priv', options)
848
+ revocationKey_old, msg = generate_private_key(options[:old_rev_pwd].to_s, options[:key_type]+'-priv', options)
692
849
  end
693
850
  else
694
- revocationKey_old, msg = decode_private_key(options[:old_rev_enc].to_s, options)
851
+ revocationKey_old = options[:old_rev_enc].to_s
695
852
  end
696
853
  else
697
854
  revocationKey_old, msg = read_private_key(options[:old_rev_key].to_s, options)
@@ -706,20 +863,21 @@ class Oydid
706
863
  else
707
864
 
708
865
  # check if provided old keys are native DID keys or delegates ==================
866
+ msg = ""
709
867
  if options[:doc_key].nil?
710
868
  if options[:doc_enc].nil?
711
- old_privateKey, msg = generate_private_key(options[:old_doc_pwd].to_s, 'ed25519-priv', options)
869
+ old_privateKey, msg = generate_private_key(options[:old_doc_pwd].to_s, options[:key_type]+'-priv', options)
712
870
  else
713
- old_privateKey, msg = decode_private_key(options[:old_doc_enc].to_s, options)
871
+ old_privateKey = options[:old_doc_enc].to_s
714
872
  end
715
873
  else
716
874
  old_privateKey, msg = read_private_key(options[:old_doc_key].to_s, options)
717
875
  end
718
876
  if options[:rev_key].nil?
719
877
  if options[:rev_enc].nil?
720
- old_revocationKey, msg = generate_private_key(options[:old_rev_pwd].to_s, 'ed25519-priv', options)
878
+ old_revocationKey, msg = generate_private_key(options[:old_rev_pwd].to_s, options[:key_type]+'-priv', options)
721
879
  else
722
- old_revocationKey, msg = decode_private_key(options[:old_rev_enc].to_s, options)
880
+ old_revocationKey = options[:old_rev_enc].to_s
723
881
  end
724
882
  else
725
883
  old_revocationKey, msg = read_private_key(options[:old_rev_key].to_s, options)
@@ -772,30 +930,6 @@ class Oydid
772
930
  return [nil, "cannot decrypt revocation log entry: " + msg]
773
931
  end
774
932
  end # compare old keys with existing DID Document
775
-
776
- # if options[:rev_pwd].nil?
777
- # if options[:rev_enc].nil?
778
- # revocationKey, msg = read_private_key(options[:rev_key].to_s, options)
779
- # else
780
- # revocationKey, msg = decode_private_key(options[:rev_enc].to_s, options)
781
- # end
782
- # else
783
- # revocationKey, msg = generate_private_key(options[:rev_pwd].to_s, 'ed25519-priv', options)
784
- # end
785
- # # re-build revocation document
786
- # did_old_doc = did_info["doc"]["doc"]
787
- # ts_old = did_info["log"].last["ts"]
788
- # publicKey_old = public_key(privateKey_old, options).first
789
- # pubRevoKey_old = public_key(revocationKey_old, options).first
790
- # did_key_old = publicKey_old + ":" + pubRevoKey_old
791
- # subDid = {"doc": did_old_doc, "key": did_key_old}.to_json
792
- # subDidHash = multi_hash(canonical(subDid), LOG_HASH_OPTIONS).first
793
- # signedSubDidHash = sign(subDidHash, revocationKey_old, options).first
794
- # revocationLog = {
795
- # "ts": ts_old,
796
- # "op": 1, # REVOKE
797
- # "doc": subDidHash,
798
- # "sig": signedSubDidHash }.transform_keys(&:to_s).to_json
799
933
  end
800
934
 
801
935
  if revocationLog.nil?
@@ -997,38 +1131,89 @@ class Oydid
997
1131
  end
998
1132
  end
999
1133
 
1134
+ oyd_context = ["https://www.w3.org/ns/did/v1"]
1135
+ pubkey = multi_decode(pubDocKey).first
1136
+ if pubkey.bytes.length == 34
1137
+ code = pubkey.bytes.first
1138
+ digest = pubkey[-32..]
1139
+ else
1140
+ if pubkey.start_with?("\x80\x24".dup.force_encoding('ASCII-8BIT'))
1141
+ code = 4608 # Bytes 0x80 0x24 sind das Varint-Encoding des Multicodec-Codes 0x1200 (p256-pub)
1142
+ # 4608 == Oydid.read_varint("\x80$") oder "\x80\x24".force_encoding('ASCII-8BIT')
1143
+ else
1144
+ code = pubkey.unpack('n').first
1145
+ end
1146
+ digest = pubkey[-1*(pubkey.bytes.length-2)..]
1147
+ end
1148
+ case Multicodecs[code].name
1149
+ when 'ed25519-pub'
1150
+ oyd_context << "https://w3id.org/security/suites/ed25519-2020/v1"
1151
+ when 'p256-pub'
1152
+ oyd_context << "https://w3id.org/security/suites/jws-2020/v1"
1153
+ else
1154
+ return {"error": "unsupported key codec (" + Multicodecs[code].name.to_s + ")"}
1155
+ end
1156
+
1000
1157
  wd = {}
1001
1158
  if didDoc["doc"].is_a?(Hash)
1002
1159
  if didDoc["doc"]["@context"].nil?
1003
- wd["@context"] = ["https://www.w3.org/ns/did/v1", "https://w3id.org/security/suites/ed25519-2020/v1"]
1160
+ wd["@context"] = oyd_context
1004
1161
  else
1005
1162
  if didDoc["doc"]["@context"].is_a?(Array)
1006
- wd["@context"] = (["https://www.w3.org/ns/did/v1", "https://w3id.org/security/suites/ed25519-2020/v1"] + didDoc["doc"]["@context"]).uniq
1163
+ wd["@context"] = (oyd_context + didDoc["doc"]["@context"]).uniq
1007
1164
  else
1008
- wd["@context"] = (["https://www.w3.org/ns/did/v1", "https://w3id.org/security/suites/ed25519-2020/v1", didDoc["doc"]["@context"]]).uniq
1165
+ oyd_context << didDoc["doc"]["@context"]
1166
+ wd["@context"] = oyd_context.uniq
1009
1167
  end
1010
1168
  didDoc["doc"].delete("@context")
1011
1169
  end
1012
1170
  else
1013
- wd["@context"] = ["https://www.w3.org/ns/did/v1", "https://w3id.org/security/suites/ed25519-2020/v1"]
1171
+ wd["@context"] = oyd_context
1014
1172
  end
1015
1173
  wd["id"] = percent_encode(did)
1016
- wd["verificationMethod"] = [{
1017
- "id": did + "#key-doc",
1018
- "type": "Ed25519VerificationKey2020",
1019
- "controller": did,
1020
- "publicKeyMultibase": pubDocKey
1021
- },{
1022
- "id": did + "#key-rev",
1023
- "type": "Ed25519VerificationKey2020",
1024
- "controller": did,
1025
- "publicKeyMultibase": pubRevKey
1026
- }]
1174
+ case Multicodecs[code].name
1175
+ when 'ed25519-pub'
1176
+ wd["verificationMethod"] = [{
1177
+ "id": did + "#key-doc",
1178
+ "type": "Ed25519VerificationKey2020",
1179
+ "controller": did,
1180
+ "publicKeyMultibase": pubDocKey
1181
+ },{
1182
+ "id": did + "#key-rev",
1183
+ "type": "Ed25519VerificationKey2020",
1184
+ "controller": did,
1185
+ "publicKeyMultibase": pubRevKey
1186
+ }]
1187
+ when 'p256-pub'
1188
+ pubDocKey_jwk, msg = public_key_to_jwk(pubDocKey)
1189
+ if pubDocKey_jwk.nil?
1190
+ return {"error": "document key: " + msg.to_s}
1191
+ end
1192
+ pubRevKey_jwk, msg = public_key_to_jwk(pubRevKey)
1193
+ if pubRevKey_jwk.nil?
1194
+ return {"error": "revocation key: " + msg.to_s}
1195
+ end
1196
+ wd["verificationMethod"] = [{
1197
+ "id": did + "#key-doc",
1198
+ "type": "JsonWebKey2020",
1199
+ "controller": did,
1200
+ "publicKeyJwk": pubDocKey_jwk
1201
+ },{
1202
+ "id": did + "#key-rev",
1203
+ "type": "JsonWebKey2020",
1204
+ "controller": did,
1205
+ "publicKeyJwk": pubRevKey_jwk
1206
+ }]
1207
+ else
1208
+ return {"error": "unsupported key codec (" + Multicodecs[code].name.to_s + ")"}
1209
+ end
1210
+
1027
1211
  if !delegateDocKeys.nil? && delegateDocKeys.count > 0
1028
1212
  i = 0
1029
1213
  wd["capabilityDelegation"] = []
1030
1214
  delegateDocKeys.each do |key|
1031
1215
  i += 1
1216
+
1032
1217
  delegaton_object = {
1033
1218
  "id": did + "#key-delegate-doc-" + i.to_s,
1034
1219
  "type": "Ed25519VerificationKey2020",
@@ -1082,7 +1267,10 @@ class Oydid
1082
1267
  end
1083
1268
  wdf = { "id": did + "#payload",
1084
1269
  "type": "Custom",
1085
- "serviceEndpoint": location }.merge(wdf)
1270
+ "serviceEndpoint": location }.transform_keys(&:to_s).merge(wdf)
1271
+ if wdf["id"][0] == '#'
1272
+ wdf["id"] = did + wdf["id"]
1273
+ end
1086
1274
  wd["service"] = [wdf] + wd["service"].drop(1)
1087
1275
  end
1088
1276
  else
@@ -1090,42 +1278,33 @@ class Oydid
1090
1278
  if didDoc["doc"].is_a?(Hash)
1091
1279
  if didDoc["doc"] != {}
1092
1280
  didDoc = didDoc["doc"]
1093
- if didDoc["authentication"].to_s != ""
1094
- new_authentication = []
1095
- didDoc["authentication"].each do |el|
1096
- new_el = el.transform_keys(&:to_s)
1097
- new_el["id"] = percent_encode(did) + new_el["id"]
1098
- new_authentication << new_el
1099
- end unless didDoc["authentication"].nil?
1100
- if new_authentication.length > 0
1101
- wd["authentication"] = new_authentication
1102
- didDoc.delete("authentication")
1103
- end
1104
- end
1105
- if didDoc["assertionMethod"].to_s != ""
1106
- wd["assertionMethod"] = didDoc["assertionMethod"]
1107
- didDoc.delete("assertionMethod")
1108
- end
1109
- if didDoc["keyAgreement"].to_s != ""
1110
- new_keyAgreement = []
1111
- didDoc["keyAgreement"].each do |el|
1112
- new_el = el.transform_keys(&:to_s)
1113
- new_el["id"] = percent_encode(did) + new_el["id"]
1114
- new_keyAgreement << new_el
1115
- end unless didDoc["keyAgreement"].nil?
1116
- if new_keyAgreement.length > 0
1117
- wd["keyAgreement"] = new_keyAgreement
1118
- didDoc.delete("keyAgreement")
1281
+ # special handling for Verification Methods
1282
+ vms = [ "authentication",
1283
+ "assertionMethod",
1284
+ "keyAgreement",
1285
+ "capabilityInvocation",
1286
+ "capabilityDelegation" ]
1287
+
1288
+ vms.each do |vm|
1289
+ if didDoc[vm].to_s != ""
1290
+ new_entries = []
1291
+ didDoc[vm].each do |el|
1292
+ if el.is_a?(String)
1293
+ new_entries << percent_encode(did) + el
1294
+ else
1295
+ new_el = el.transform_keys(&:to_s)
1296
+ new_el["id"] = percent_encode(did) + new_el["id"]
1297
+ new_entries << new_el
1298
+ end
1299
+ end unless didDoc[vm].nil?
1300
+ if new_entries.length > 0
1301
+ wd[vm] = new_entries
1302
+ else
1303
+ wd[vm] = didDoc[vm]
1304
+ end
1305
+ didDoc.delete(vm)
1119
1306
  end
1120
1307
  end
1121
- if didDoc["capabilityInvocation"].to_s != ""
1122
- wd["capabilityInvocation"] = didDoc["capabilityInvocation"]
1123
- didDoc.delete("capabilityInvocation")
1124
- end
1125
- if didDoc["capabilityDelegation"].to_s != ""
1126
- wd["capabilityDelegation"] = didDoc["capabilityDelegation"]
1127
- didDoc.delete("capabilityDelegation")
1128
- end
1129
1308
  if didDoc["alsoKnownAs"].to_s != ""
1130
1309
  if didDoc["alsoKnownAs"].is_a?(Array)
1131
1310
  dda = didDoc["alsoKnownAs"]