public static IEnumerable <string> ToRdf(JToken token, JsonLdProcessorOptions options) { var jsonLdParser = new JsonLdParser(options); var store = new TripleStore(); jsonLdParser.Load(store, new StringReader(token.ToString(Newtonsoft.Json.Formatting.None))); var nqWriter = new NQuadsWriter(NQuadsSyntax.Rdf11); using var expectedTextWriter = new System.IO.StringWriter(); nqWriter.Save(store, expectedTextWriter); return(expectedTextWriter.ToString() .Split(expectedTextWriter.NewLine) .Select(x => x.Trim()) .Where(x => !string.IsNullOrWhiteSpace(x)) .OrderBy(x => x)); }
public override async Task <JObject> UpdateAsync(JObject proof, ProofOptions options) { proof = await base.UpdateAsync(proof, options); // no capability chain given, attempt to compute from parent if (CapabilityChain == null) { var processorOptions = new JsonLdProcessorOptions { CompactToRelative = false, DocumentLoader = options.DocumentLoader.Load }; var capability = await Utils.FetchInSecurityContextAsync( options.Input, false, processorOptions); CapabilityChain = await Utils.ComputeCapabilityChainAsync( capability, processorOptions); } proof["capabilityChain"] = new JArray(CapabilityChain); return(proof); }
public async Task <JToken> CreateProofAsync(CreateProofOptions options) { if (options.VerificationMethod is null) { throw new Exception("Verification method is required."); } if (options.ProofPurpose is null) { throw new Exception("Proof purpose is required."); } if (options.LdSuiteType is null) { throw new Exception("Suite type is required."); } var suite = suiteFactory.GetSuite(options.LdSuiteType) ?? throw new Exception($"Suite not found for type '{options.LdSuiteType}'"); var processorOptions = new JsonLdProcessorOptions { CompactToRelative = false, DocumentLoader = documentLoader.GetDocumentLoader() }; var original = options.Document.DeepClone(); if (options.CompactProof) { options.Document = JsonLdProcessor.Compact( input: options.Document, context: Constants.SECURITY_CONTEXT_V2_URL, options: processorOptions); } original["proof"] = await suite.CreateProofAsync(options, processorOptions); return(original); }
public bool VerifyProof(VerifyProofOptions options, JsonLdProcessorOptions processorOptions) { options.Proof["type"] = "https://w3c-ccg.github.io/ldp-bbs2020/context/v1#BbsBlsSignature2020"; var documentStatements = BbsBlsSignature2020Suite.CreateVerifyDocumentData(options.Document, processorOptions); var proofStatements = BbsBlsSignature2020Suite.CreateVerifyProofData(options.Proof, processorOptions); var transformedInputDocumentStatements = documentStatements.Select(TransformIdToBlankNode).ToArray(); var statementsToVerify = proofStatements.Concat(transformedInputDocumentStatements); var verificationMethod = BbsBlsSignature2020Suite.GetVerificationMethod(options.Proof, processorOptions); var proofData = Convert.FromBase64String(options.Proof["proofValue"].ToString()); var nonce = options.Proof["nonce"].ToString(); var verifyResult = BbsProvider.VerifyProof(new VerifyProofRequest( publicKey: verificationMethod.ToBlsKeyPair().GeyBbsKeyPair((uint)statementsToVerify.Count()), proof: proofData, messages: GetIndexedMessages(statementsToVerify.ToArray()).ToArray(), nonce: nonce)); return(verifyResult == SignatureProofStatus.Success); }
/// <summary> /// Creates a new GZipped JSON-LD parser with a specific set of <see cref="JsonLdProcessorOptions"/>. /// </summary> /// <param name="parserOptions">The options to pass to the underlying <see cref="JsonLdParser"/></param> public GZippedJsonLdParser(JsonLdProcessorOptions parserOptions) : base(new JsonLdParser(parserOptions)) { }
/// <summary> /// Create a new processor instance that uses the specified processor options. /// </summary> /// <param name="options"></param> /// <param name="warnings">The list to add any generated warnings to</param> public ProcessorBase(JsonLdProcessorOptions options, IList <JsonLdProcessorWarning> warnings) { Options = options; Warnings = warnings; }
/// <summary> /// Create an instace of the parser configured with the provided parser options /// </summary> /// <param name="parserOptions"></param> public JsonLdParser(JsonLdProcessorOptions parserOptions) { ParserOptions = parserOptions; }
public Task <JToken> CreateProofAsync(CreateProofOptions options, JsonLdProcessorOptions processorOptions) => Task.FromResult(CreateProof(options, processorOptions));
public Task <bool> VerifyProofAsync(VerifyProofOptions options, JsonLdProcessorOptions processorOptions) => Task.FromResult(VerifyProof(options, processorOptions));
/// <summary> /// Creates a `capabilityChain` for delegating the given capability. /// </summary> /// <param name="capability"></param> /// <param name="processorOptions"></param> /// <returns></returns> public static Task <IEnumerable <string> > ComputeCapabilityChainAsync(JObject capability, JsonLdProcessorOptions processorOptions) { if (capability["parentCapability"] == null) { throw new Exception("Cannot compute capability chain; capability has no 'parentCapability"); } // TODO throw new NotImplementedException("Cannot compute capability chain."); }
/// <summary> /// Fetches a JSON-LD document from a URL and, if necessary, compacts it to /// the security v2 context. /// </summary> /// <param name="document"></param> /// <param name="isRoot"></param> /// <param name="options"></param> /// <returns></returns> public static async Task <JObject> FetchInSecurityContextAsync(JToken document, bool isRoot = false, JsonLdProcessorOptions options = null) { await Task.Yield(); if (document.Type == JTokenType.Object && document["@context"]?.Value <string>() == Constants.SECURITY_CONTEXT_V2_URL && !isRoot) { return(document as JObject); } return(JsonLdProcessor.Compact(document, Constants.SECURITY_CONTEXT_V2_URL, options)); }
/// <summary> /// Verifies the capability chain, if any, attached to the given capability. /// </summary> /// <param name="capability"></param> /// <returns></returns> public static async Task <JToken> VerifyCapabilityChain(JToken capability, PurposeOptions purposeOptions, JsonLdProcessorOptions options = null) { /* Verification process is: * 1. Fetch capability if only its ID was passed. * 1.1. Ensure `capabilityAction` is allowed. * 2. Get the capability delegation chain for the capability. * 3. Validate the capability delegation chain. * 4. Verify the root capability: * 4.1. Check the expected target, if one was specified. * 4.2. Ensure that the caveats are met on the root capability. * 4.3. Ensure root capability is expected and has no invocation target. * 5. If `excludeGivenCapability` is not true, then we need to verify the * capability delegation proof on `capability`, so add it to the chain to * get processed below. * 6. For each capability `cap` in the chain, verify the capability delegation * proof on `cap`. This will validate everything else for `cap` including * that caveats are met. * * Note: We start verifying a capability from its root of trust (the * beginning or head of the capability chain) as this approach limits an * attacker's ability to waste our time and effort traversing from the tail * to the head. */ // 1. Fetch capability if only its ID was passed. capability = await FetchInSecurityContextAsync(capability, false, options); //capability = new CapabilityDelegation(cap as JObject); // TODO: Add allowed action validation // 2. Get the capability delegation chain for the capability. var capabilityChain = GetCapabilityChain(capability); // 3. Validate the capability delegation chain. ValidateCapabilityChain(capability, capabilityChain); // 4. Verify root capability (note: it must *always* be dereferenced since // it does not need to have a delegation proof to vouch for its authenticity // ... dereferencing it prevents adversaries from submitting an invalid // root capability that is accepted): var isRoot = !capabilityChain.Any(); var rootCapability = isRoot ? capability : capabilityChain.First(); capabilityChain = capabilityChain.Skip(1).ToArray(); rootCapability = await Utils.FetchInSecurityContextAsync(rootCapability, isRoot, null); // 4.1. Check the expected target, if one was specified. if (purposeOptions.ExpectedTarget != null) { var target = GetTarget(rootCapability); if (target != purposeOptions.ExpectedTarget) { throw new Exception($"Expected target ({purposeOptions.ExpectedTarget}) does not match " + $"root capability target({target})."); } } // 4.2. Ensure that the caveats are met on the root capability. // TODO: Add caveats // 4.3. Ensure root capability is expected and has no invocation target. // run root capability checks (note that these will only be run once // because the `verifiedParentCapability` parameter stops recursion // from happening below) // ensure that the invocation target matches the root capability or, // if `expectedRootCapability` is present, that it matches that if (purposeOptions.ExpectedRootCapability != null) { if (purposeOptions.ExpectedRootCapability != rootCapability["id"].Value <string>()) { throw new Exception($"Expected root capability ({purposeOptions.ExpectedRootCapability}) does not " + $"match actual root capability({rootCapability["id"]})."); } } else if (GetTarget(rootCapability) != rootCapability["id"].Value <string>()) { throw new Exception("The root capability must not specify a different " + "invocation target."); } // root capability now verified var verifiedParentCapability = rootCapability; // if verifying a delegation proof and we're at the root, exit early if (isRoot) { return(verifiedParentCapability); } // create a document loader that will use properly embedded capabilities var documentLoader = new CachingDocumentLoader(Array.Empty <IDocumentResolver>()); var next = capabilityChain; while (next.Any()) { // the only capability that may be embedded (if the zcap is valid) is // the last one in the chain, if it is embedded, add it to `dlMap` and // recurse into its chain and loop to collect all embedded zcaps var cap = next.Last(); if (!(cap is JObject)) { break; } if (cap["@context"] == null) { // the capabilities in the chain are already in the security context // if no context has been specified cap["@context"] = Constants.SECURITY_CONTEXT_V2_URL; } // Transforms the `capability` into the security context (the native // context this code uses) so we can process it cleanly and then // verifies the capability delegation proof on `capability`. This allows // capabilities to be expressed using custom contexts. cap = await FetchInSecurityContextAsync(cap, false, options); documentLoader.AddCached(cap["id"].Value <string>(), cap as JObject); next = GetCapabilityChain(cap); } options.DocumentLoader = documentLoader.Load; // 5. If `excludeGivenCapability` is not true, then we need to verify the // capability delegation proof on `capability`, so add it to the chain to // get processed below. If an `inspectCapabilityChain` handler has been // provided, the verify results are required on all capabilities. // TODO: Add support for `excludeGivenCapability` // 6. For each capability `cap` in the chain, verify the capability // delegation proof on `cap`. This will validate everything else for // `cap` including that caveats are met. // note that `verifiedParentCapability` will prevent repetitive checking // of the same segments of the chain (once a parent is verified, its chain // is not checked again when checking its children) for (int i = 0; i < capabilityChain.Count(); i++) { var cap = capabilityChain.ElementAt(i); cap = await FetchInSecurityContextAsync(cap, false, options); var verifyResult = LdSignatures.VerifyAsync(cap, new ProofOptions { Suite = purposeOptions.Suite, Purpose = new CapabilityDelegationProofPurpose { Options = new PurposeOptions { ExpectedTarget = purposeOptions.ExpectedTarget, ExpectedRootCapability = purposeOptions.ExpectedRootCapability }, VerifiedParentCapability = verifiedParentCapability }, DocumentLoader = documentLoader, CompactProof = false }); } return(null); }
public static (JToken, IEnumerable <JObject>) GetProofs(this JToken document, JsonLdProcessorOptions options, bool compactProof = true, string proofPropertyName = "proof") { if (compactProof) { document = JsonLdProcessor.Compact(document, Constants.SECURITY_CONTEXT_V2_URL, options); } var proofs = document[proofPropertyName]; (document as JObject).Remove(proofPropertyName); return(document, proofs switch { JObject _ => new[] { proofs as JObject }, JArray _ => proofs.Select(x => x as JObject), _ => throw new Exception("Unexpected proof type") });