oydid 0.6.7 → 0.8.0

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
@@ -26,7 +26,12 @@ class Oydid
26
26
  LOCATION_PREFIX = "@"
27
27
  DEFAULT_LOCATION = "https://oydid.ownyourdata.eu"
28
28
  DEFAULT_DIGEST = "sha2-256"
29
- SUPPORTED_DIGESTS = ["sha2-256", "sha2-512", "sha3-224", "sha3-256", "sha3-384", "sha3-512", "blake2b-16", "blake2b-32", "blake2b-64"]
29
+ # BLAKE2b digests are named by digest size in BYTES here (house convention,
30
+ # e.g. "blake2b-16" is a 16 byte / 128 bit digest). This deliberately
31
+ # deviates from the multicodec registry, where blake2b-N counts bits.
32
+ SUPPORTED_DIGESTS = ["sha2-256", "sha2-512", "sha3-224", "sha3-256", "sha3-384", "sha3-512",
33
+ "blake2b-16", "blake2b-17", "blake2b-18", "blake2b-19", "blake2b-20",
34
+ "blake2b-21", "blake2b-22", "blake2b-23", "blake2b-32", "blake2b-64"]
30
35
  DEFAULT_ENCODING = "base58btc"
31
36
  SUPPORTED_ENCODINGS = ["base16", "base32", "base58btc", "base64"]
32
37
  LOG_HASH_OPTIONS = {:digest => "sha2-256", :encode => "base58btc"}
@@ -34,6 +39,24 @@ class Oydid
34
39
  JWS_SECURITY_SUITE = "https://w3id.org/security/suites/jws-2020/v1"
35
40
  DEFAULT_PUBLIC_RESOLVER = "https://dev.uniresolver.io/1.0/identifiers/"
36
41
 
42
+ # Single-byte multicodec codes for the intermediate BLAKE2b digest sizes
43
+ # (17-23 bytes), needed to keep a did:oyd identifier short enough for the
44
+ # 50 character URL limit of the EU Digital Product Passport registry.
45
+ #
46
+ # These sizes cannot take their code from Multicodecs[]: multi_hash packs
47
+ # the code into a single byte, which effectively truncates the registry's
48
+ # two-byte blake2b codes to their low byte - and those collide with the SHA
49
+ # codes already in use (0xb212 -> 0x12 = sha2-256, 0xb214 -> 0x14 =
50
+ # sha3-512, 0xb216 -> 0x16 = sha3-256, 0xb217 -> 0x17 = sha3-224).
51
+ #
52
+ # Instead the free, contiguous range 0x0B-0x11 is used (code = size - 6).
53
+ # Codes are kept low and single-byte on purpose: the value of the leading
54
+ # byte feeds into the base58btc length, and a low code saves a character.
55
+ BLAKE2B_EXTRA_CODES = {
56
+ 17 => 0x0B, 18 => 0x0C, 19 => 0x0D, 20 => 0x0E,
57
+ 21 => 0x0F, 22 => 0x10, 23 => 0x11
58
+ }.freeze
59
+
37
60
  # full Multicodecs table: https://github.com/multiformats/multicodec/blob/master/table.csv
38
61
  # Multicodecs.register(code: 0x1305, name: 'rsa-priv', tag: 'key')
39
62
  # Multicodecs.register(code: 0x1205, name: 'rsa-pub', tag: 'key')
@@ -199,54 +222,98 @@ class Oydid
199
222
  ts = options[:ts]
200
223
  end
201
224
 
202
- options[:cmsm2] = false
225
+ # signatures collected from the client so far (CMSM only)
226
+ cmsm_sig_rev = nil
227
+ cmsm_sig_doc = nil
228
+ cmsm_sig_create = nil
229
+ cmsm_log_revoke_old = nil
230
+ cmsm_resume = options[:cmsm] && options[:cmsm_session].to_s != ""
231
+
203
232
  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
233
+ # A CMSM flow is identified by a session handle, not by the public
234
+ # key: the same key may legitimately be reused across flows, and
235
+ # keying the intermediate data on it made a second flow overwrite
236
+ # the first one. Absence of a session means "start a new flow".
237
+ if !cmsm_resume
238
+ if did_doc["key"].nil?
239
+ return [nil, nil, nil, "CMSM requires public key"]
240
+ end
241
+ cmsm_keys = did_doc["key"].split(':')
242
+ did_doc.delete("key")
243
+ if did_doc == {}
244
+ did_doc = nil
245
+ end
246
+ case cmsm_keys.count
247
+ when 2
248
+ # both keys are managed by the client - the revocation record
249
+ # of the new document has to be signed by the client as well
250
+ publicKey = cmsm_keys[0]
251
+ pubRevoKey = cmsm_keys[1]
252
+ revocationKey = nil
253
+ when 1
254
+ # only the document key is client-managed; the revocation key
255
+ # is generated here and stays with this process
256
+ publicKey = cmsm_keys[0]
257
+ revocationKey, msg = generate_private_key("", options[:key_type]+'-priv', options)
258
+ if revocationKey.nil?
259
+ return [nil, nil, nil, "cannot generate revocation key: " + msg.to_s]
260
+ end
261
+ pubRevoKey = public_key(revocationKey, options).first
262
+ else
263
+ return [nil, nil, nil, "CMSM accepts at most two public keys"]
264
+ end
216
265
  else
217
- return [nil, nil, nil, "CMSM with multiple keys is not yet supported"]
218
- end
266
+ # continue a persisted flow: the request carries the session and
267
+ # exactly one new signature, which fills the next open slot
268
+ incoming_sig = options[:sig]
269
+ if incoming_sig.to_s == ""
270
+ incoming_sig = did_doc["opt"]["sig"] rescue nil
271
+ end
272
+ if incoming_sig.to_s == ""
273
+ return [nil, nil, nil, "missing signature in CMSM flow (sig)"]
274
+ end
219
275
 
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?
276
+ payload, msg = check_cmsm(options[:cmsm_session], options)
277
+ if payload.nil?
278
+ if msg.to_s == ""
279
+ msg = "unknown or expired CMSM session"
280
+ end
281
+ return [nil, nil, nil, msg]
282
+ end
223
283
  if payload.is_a?(String)
224
284
  payload = JSON.parse(payload) rescue nil
225
285
  end
226
286
  if payload.nil?
227
287
  return [nil, nil, nil, "invalid persisted data in CMSM flow"]
228
288
  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
289
+ payload = payload.transform_keys(&:to_s)
244
290
 
291
+ privateKey = nil
292
+ publicKey = payload["publicKey"]
293
+ pubRevoKey = payload["pubRevoKey"]
245
294
  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"]
295
+ did_doc = payload["did_doc"]
296
+ cmsm_sig_rev = payload["sig_rev"]
297
+ cmsm_sig_doc = payload["sig_doc"]
298
+ cmsm_sig_create = payload["sig_create"]
299
+ # the update context is only sent in phase 1
300
+ if !payload["log_revoke_old"].nil?
301
+ options[:log_revoke_old] = payload["log_revoke_old"]
302
+ end
303
+ # the timestamp and the location are part of every hash in the
304
+ # flow and must not be recomputed per phase
305
+ ts = payload["ts"].to_i
306
+ doc_location = payload["doc_location"]
307
+
308
+ if revocationKey.to_s == "" && cmsm_sig_rev.to_s == ""
309
+ cmsm_sig_rev = incoming_sig
310
+ elsif cmsm_sig_doc.to_s == ""
311
+ cmsm_sig_doc = incoming_sig
312
+ elsif cmsm_sig_create.to_s == ""
313
+ cmsm_sig_create = incoming_sig
314
+ else
315
+ return [nil, nil, nil, "CMSM session is already complete"]
316
+ end
250
317
  end
251
318
  else
252
319
  # key management
@@ -299,6 +366,27 @@ class Oydid
299
366
  log_old = did_info["log"]
300
367
 
301
368
  # check if provided old keys are native DID keys or delegates ==================
369
+ if options[:cmsm]
370
+ # The old private keys are with the client, so nothing can be
371
+ # derived from them here. The old public keys come from the DID
372
+ # document just resolved, and the revocation record of the current
373
+ # document is supplied by the client - it received that record when
374
+ # the DID was created or last updated. Rebuilding it here is not
375
+ # possible: it needs a signature by the old revocation key.
376
+ old_privateKey = nil
377
+ old_revocationKey = nil
378
+ old_did_key = did_info["doc"]["key"].to_s
379
+ old_publicDocKey = old_did_key.split(":").first.to_s
380
+ old_publicRevKey = old_did_key.split(":").last.to_s
381
+
382
+ verified, vmsg = verify_revocation_log(did_info, options[:log_revoke_old],
383
+ "log_revoke_old", options)
384
+ if verified.nil?
385
+ return [nil, nil, nil, vmsg]
386
+ end
387
+ revocationLog = verified.to_json
388
+ cmsm_log_revoke_old = verified
389
+ else
302
390
  tmp_old_doc_did10 = did10_old + "_private_key.enc" rescue ""
303
391
  old_privateKey, msg = getPrivateKey(options[:old_doc_enc], options[:old_doc_pwd], options[:old_doc_key], tmp_old_doc_did10, options)
304
392
  tmp_old_rev_did10 = did10_old + "_revocation_key.enc" rescue ""
@@ -352,6 +440,7 @@ class Oydid
352
440
  return [nil, nil, nil, "cannot decrypt revocation log entry: " + msg]
353
441
  end
354
442
  end # compare old keys with existing DID Document
443
+ end # CMSM or self-managed
355
444
 
356
445
  revoc_log = JSON.parse(revocationLog)
357
446
  revoc_log["previous"] = [
@@ -360,13 +449,15 @@ class Oydid
360
449
  ]
361
450
  prev_hash = [multi_hash(canonical(revoc_log), LOG_HASH_OPTIONS).first]
362
451
  end
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
452
+ if !options[:cmsm]
453
+ publicKey = public_key(privateKey, options).first
454
+ pubRevoKey = public_key(revocationKey, options).first
455
+ end
456
+ did_key = publicKey + ":" + pubRevoKey
369
457
 
458
+ # the document is assembled once, in the first phase of a CMSM flow -
459
+ # afterwards it comes back from the session unchanged
460
+ if !cmsm_resume
370
461
  if options[:keyAgreement]
371
462
  if did_doc.nil?
372
463
  did_doc = {}
@@ -392,44 +483,52 @@ class Oydid
392
483
  did_doc[:authentication] = ["#key-doc"]
393
484
  did_doc = did_doc.transform_keys(&:to_s)
394
485
  end
486
+ end
395
487
 
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
488
+ # build new revocation document
489
+ subDid = {"doc": did_doc, "key": did_key}.to_json
490
+ retVal = multi_hash(canonical(subDid), LOG_HASH_OPTIONS)
491
+ if retVal.first.nil?
492
+ return [nil, nil, nil, retVal.last]
493
+ end
494
+ subDidHash = retVal.first
495
+
496
+ if options[:cmsm] && revocationKey.to_s == "" && cmsm_sig_rev.to_s == ""
497
+ # the revocation key is managed by the client, so the revocation
498
+ # record of the new document has to be signed there. Its signature
499
+ # feeds into r1 and thus into every later hash, which is why this
500
+ # cannot be asked for together with the document-key signature.
501
+ return cmsm_challenge(subDidHash, "key-rev", cmsm_state(publicKey,
502
+ pubRevoKey, revocationKey, did_doc, ts, doc_location,
503
+ cmsm_sig_rev, cmsm_sig_doc, cmsm_sig_create,
504
+ did_old, cmsm_log_revoke_old), options)
505
+ end
506
+
507
+ if revocationKey.to_s == ""
508
+ signedSubDidHash = cmsm_sig_rev
509
+ else
403
510
  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
511
+ end
512
+ r1 = { "ts": ts,
513
+ "op": 1, # REVOKE
514
+ "doc": subDidHash,
515
+ "sig": signedSubDidHash }.transform_keys(&:to_s)
414
516
 
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)
517
+ # build termination log entry
518
+ l2_doc = multi_hash(canonical(r1), LOG_HASH_OPTIONS).first
519
+ if !doc_location.nil?
520
+ l2_doc += LOCATION_PREFIX + doc_location.to_s
521
+ end
425
522
 
426
- cmsm_doc = {
427
- cmsm: true,
428
- pk: publicKey,
429
- sign: l2_doc
430
- }
431
- return [cmsm_doc, nil, r1, "cmsm"]
523
+ if options[:cmsm]
524
+ if cmsm_sig_doc.to_s == ""
525
+ return cmsm_challenge(l2_doc, "key-doc", cmsm_state(publicKey,
526
+ pubRevoKey, revocationKey, did_doc, ts, doc_location,
527
+ cmsm_sig_rev, cmsm_sig_doc, cmsm_sig_create,
528
+ did_old, cmsm_log_revoke_old), options)
432
529
  end
530
+ l2_sig = cmsm_sig_doc
531
+ else
433
532
  l2_sig = sign(l2_doc, privateKey, options).first
434
533
  end
435
534
 
@@ -480,7 +579,17 @@ class Oydid
480
579
  log_revoke_encrypted_array = nil
481
580
  l1_sig = nil
482
581
  if operation_mode == 3 # UPDATE
483
- if !options[:cmsm]
582
+ if options[:cmsm]
583
+ if cmsm_sig_create.to_s == ""
584
+ # the transition has to be authorised by the key of the
585
+ # document being replaced, not by the new one
586
+ return cmsm_challenge(l1_doc, "key-doc-old", cmsm_state(publicKey,
587
+ pubRevoKey, revocationKey, did_doc, ts, doc_location,
588
+ cmsm_sig_rev, cmsm_sig_doc, cmsm_sig_create,
589
+ did_old, cmsm_log_revoke_old), options)
590
+ end
591
+ l1_sig = cmsm_sig_create
592
+ else
484
593
  l1_sig = sign(l1_doc, old_privateKey, options).first
485
594
  end
486
595
  l1 = { "ts": ts,
@@ -502,7 +611,18 @@ class Oydid
502
611
  end
503
612
  end unless options[:confirm_logs].nil?
504
613
  else
505
- if !options[:cmsm]
614
+ if options[:cmsm]
615
+ if cmsm_sig_create.to_s == ""
616
+ # l1_doc is only known once the TERMINATE entry is signed, so
617
+ # the CREATE signature cannot be collected any earlier. Without
618
+ # this phase the CREATE log entry would stay unsigned.
619
+ return cmsm_challenge(l1_doc, "key-doc", cmsm_state(publicKey,
620
+ pubRevoKey, revocationKey, did_doc, ts, doc_location,
621
+ cmsm_sig_rev, cmsm_sig_doc, cmsm_sig_create,
622
+ did_old, cmsm_log_revoke_old), options)
623
+ end
624
+ l1_sig = cmsm_sig_create
625
+ else
506
626
  l1_sig = sign(l1_doc, privateKey, options).first
507
627
  end
508
628
  l1 = { "ts": ts,
@@ -589,12 +709,118 @@ class Oydid
589
709
 
590
710
  end
591
711
 
592
- def self.persist_cmsm(pubkey, payload, options)
712
+ # Verify a revocation record supplied by a client against the DID it claims
713
+ # to revoke. Used wherever the private revocation key is not available here:
714
+ # a CMSM update (revoking the document being replaced) and a client-managed
715
+ # deactivation.
716
+ #
717
+ # Three things have to line up, and the third is the strict one: the hash of
718
+ # the record is committed in the TERMINATE entry of the current document, so
719
+ # a record from any other DID - or a re-signed one that happens to differ -
720
+ # cannot pass.
721
+ #
722
+ # Returns the normalised record (without "previous") or [nil, message].
723
+ def self.verify_revocation_log(did_info, log_revoke, field, options = {})
724
+ record = log_revoke
725
+ record = (JSON.parse(record) rescue nil) if record.is_a?(String)
726
+ record = record.transform_keys(&:to_s) if record.is_a?(Hash)
727
+ if !record.is_a?(Hash)
728
+ return [nil, "missing revocation record (" + field + ")"]
729
+ end
730
+
731
+ did_key = did_info["doc"]["key"].to_s
732
+ pubRevKey = did_key.split(":").last.to_s
733
+ subDid = {"doc": did_info["doc"]["doc"], "key": did_key}.to_json
734
+ subDidHash = multi_hash(canonical(subDid), LOG_HASH_OPTIONS).first
735
+
736
+ if record["doc"].to_s != subDidHash.to_s
737
+ return [nil, field + " does not match the current DID document"]
738
+ end
739
+ sig_ok, _msg = verify(subDidHash, record["sig"].to_s, pubRevKey)
740
+ if !sig_ok
741
+ return [nil, "invalid signature in " + field]
742
+ end
743
+
744
+ normalised = { "ts" => record["ts"],
745
+ "op" => 1, # REVOKE
746
+ "doc" => subDidHash,
747
+ "sig" => record["sig"] }
748
+
749
+ termination_doc = did_info["log"][did_info["termination_log_id"].to_i]["doc"].to_s
750
+ termination_doc = termination_doc.split(LOCATION_PREFIX).first.split(CGI.escape LOCATION_PREFIX).first
751
+ if termination_doc != multi_hash(canonical(normalised.to_json), LOG_HASH_OPTIONS).first
752
+ return [nil, field + " does not match the TERMINATE entry of the current document"]
753
+ end
754
+
755
+ [normalised, ""]
756
+ end
757
+
758
+ # link a verified revocation record into the log of the DID it revokes
759
+ def self.link_revocation_log(record, did_info)
760
+ log_old = did_info["log"]
761
+ record = record.dup
762
+ record["previous"] = [
763
+ multi_hash(canonical(log_old[did_info["doc_log_id"].to_i]), LOG_HASH_OPTIONS).first,
764
+ multi_hash(canonical(log_old[did_info["termination_log_id"].to_i]), LOG_HASH_OPTIONS).first
765
+ ]
766
+ record
767
+ end
768
+
769
+ # state of a CMSM flow that has to survive between phases. Deliberately only
770
+ # inputs and collected signatures - no derived hashes: every phase recomputes
771
+ # r1 / l2_doc / the DID from these values, so there is nothing to keep in sync.
772
+ def self.cmsm_state(publicKey, pubRevoKey, revocationKey, did_doc, ts, doc_location, sig_rev, sig_doc, sig_create, did_old = nil, log_revoke_old = nil)
773
+ {
774
+ publicKey: publicKey,
775
+ pubRevoKey: pubRevoKey,
776
+ revocationKey: revocationKey,
777
+ did_doc: did_doc,
778
+ ts: ts,
779
+ doc_location: doc_location,
780
+ sig_rev: sig_rev,
781
+ sig_doc: sig_doc,
782
+ # signature over l1_doc: the CREATE entry on create, the UPDATE entry
783
+ # on update - the latter is signed with the OLD document key
784
+ sig_create: sig_create,
785
+ # update only: which DID is being replaced, and the revocation record
786
+ # of its current document (supplied by the client in phase 1)
787
+ did_old: did_old,
788
+ log_revoke_old: log_revoke_old
789
+ }
790
+ end
791
+
792
+ # persist the state of a CMSM flow and return the next challenge: the value
793
+ # the client has to sign, and which of its keys it has to sign it with
794
+ def self.cmsm_challenge(value, with, state, options)
795
+ session, msg = persist_cmsm(options[:cmsm_session], state, options)
796
+ if session.nil?
797
+ return [nil, nil, nil, msg]
798
+ end
799
+ collected = [state[:sig_rev], state[:sig_doc], state[:sig_create]].count { |sig| sig.to_s != "" }
800
+ cmsm_doc = {
801
+ cmsm: true,
802
+ session: session,
803
+ phase: collected + 1,
804
+ pk: state[:publicKey],
805
+ sign: value,
806
+ with: with
807
+ }
808
+ return [cmsm_doc, nil, nil, "cmsm"]
809
+ end
810
+
811
+ # persist the intermediate data of a CMSM flow and return the session handle
812
+ # it is stored under. A blank session starts a new flow; the handle is
813
+ # generated here so that the local and the remote store behave identically.
814
+ def self.persist_cmsm(session, payload, options)
815
+ if session.to_s == ""
816
+ session = "cmsm-" + SecureRandom.hex(8)
817
+ end
818
+
593
819
  # in-process callers can supply a store object (responding to
594
- # #set(pubkey, payload)) to persist CMSM data in a local database
820
+ # #set(session, payload)) to persist CMSM data in a local database
595
821
  if options[:cmsm_store]
596
- options[:cmsm_store].set(pubkey, payload)
597
- return [true, ""]
822
+ options[:cmsm_store].set(session, payload)
823
+ return [session, ""]
598
824
  end
599
825
 
600
826
  doc_location = options[:doc_location]
@@ -604,7 +830,8 @@ class Oydid
604
830
  doc_location = doc_location.sub("%3A%2F%2F","://").sub("%3A", ":")
605
831
 
606
832
  my_body = {
607
- pubkey: pubkey,
833
+ session: session,
834
+ pubkey: payload[:publicKey] || payload["publicKey"],
608
835
  payload: payload.to_json
609
836
  }
610
837
  case doc_location.to_s
@@ -615,22 +842,22 @@ class Oydid
615
842
  body: my_body.to_json )
616
843
  if retVal.code != 200
617
844
  err_msg = retVal.parsed_response("error").to_s rescue "invalid response from " + doc_location.to_s + "/cmsm"
618
- return [false, err_msg]
845
+ return [nil, err_msg]
619
846
  end
620
847
  else
621
848
  return [nil, "location not supported for persisting data in cmsm-flow"]
622
849
  end
623
- return [true, ""]
850
+ return [session, ""]
624
851
 
625
852
  end
626
853
 
627
- def self.check_cmsm(pubkey, options)
854
+ def self.check_cmsm(session, options)
628
855
  # in-process callers can supply a store object (responding to
629
- # #get(pubkey)) to read CMSM data from a local database
856
+ # #get(session)) to read CMSM data from a local database
630
857
  if options[:cmsm_store]
631
- payload = options[:cmsm_store].get(pubkey)
858
+ payload = options[:cmsm_store].get(session)
632
859
  if payload.nil?
633
- return [nil, "no persisted CMSM data for key"]
860
+ return [nil, "unknown or expired CMSM session"]
634
861
  end
635
862
  payload = payload.transform_keys(&:to_s) if payload.is_a?(Hash)
636
863
  return [payload, ""]
@@ -644,11 +871,11 @@ class Oydid
644
871
 
645
872
  case doc_location.to_s
646
873
  when /^http/
647
- retVal = HTTParty.get(doc_location + "/cmsm/" + pubkey)
874
+ retVal = HTTParty.get(doc_location + "/cmsm/" + session.to_s)
648
875
  if retVal.code != 200
649
876
  msg = retVal.parsed_response["error"].to_s rescue ""
650
877
  if msg.to_s == ""
651
- msg = "invalid response from " + doc_location.to_s + "/cmsm/" + pubkey.to_s
878
+ msg = "invalid response from " + doc_location.to_s + "/cmsm/" + session.to_s
652
879
  end
653
880
  return [nil, msg]
654
881
  end