/// <inheritdoc/> public async Task <(DidExchangeResponseMessage, ConnectionRecord)> CreateResponseAsync(IAgentContext agentContext, ConnectionRecord connectionRecord) { await connectionRecord.TriggerAsync(ConnectionTrigger.Response); var myDid = await Did.CreateAndStoreMyDidAsync(agentContext.Wallet, "{}"); connectionRecord.MyDid = DidUtils.ConvertVerkeyToDidKey(myDid.VerKey); connectionRecord.MyVk = myDid.VerKey; var provisioningRecord = await _provisioningService.GetProvisioningAsync(agentContext.Wallet); var didDoc = new AttachmentContent { Base64 = connectionRecord.MyDidDoc(provisioningRecord).ToJson().ToBase64Url() }; await didDoc.SignWithJsonWebSignature(agentContext.Wallet, myDid.VerKey); var attachment = new Attachment { Id = Guid.NewGuid().ToString(), MimeType = "application/json", Data = didDoc }; var response = new DidExchangeResponseMessage { Id = Guid.NewGuid().ToString(), Did = connectionRecord.MyDid, DidDoc = attachment }; await _recordService.UpdateAsync(agentContext.Wallet, connectionRecord); return(response, connectionRecord); }
public void CanDetectDidKey() { Assert.True(DidUtils.IsDidKey(VALID_DID_KEY)); Assert.True(DidUtils.IsDidKey(VALID_SECP256K1_0)); Assert.False(DidUtils.IsDidKey(VALID_FULL_VERKEY)); Assert.False(DidUtils.IsDidKey("")); }
public void CanDetectFullVerkey() { Assert.True(DidUtils.IsFullVerkey(VALID_FULL_VERKEY)); //Valid full verkey Assert.True(DidUtils.IsFullVerkey(ANOTHER_VALID_FULL_VERKEY)); // Indy seems to generate verkeys with less than 256bit (only 43 chars) Assert.False(DidUtils.IsFullVerkey("")); Assert.False(DidUtils.IsFullVerkey(VALID_ABBREVIATED_VERKEY)); //Valid abbreviated verkey }
/// <summary> /// Get a service decorator representation for this provisioning record /// </summary> /// <param name="record"></param> /// <param name="useDidKeyFormat"></param> /// <returns></returns> public static ServiceDecorator ToServiceDecorator(this ProvisioningRecord record, bool useDidKeyFormat = false) { return(new ServiceDecorator { ServiceEndpoint = record.Endpoint.Uri, RoutingKeys = useDidKeyFormat ? record.Endpoint.Verkey.Select(DidUtils.ConvertVerkeyToDidKey) : record.Endpoint.Verkey, RecipientKeys = new [] { useDidKeyFormat?DidUtils.ConvertVerkeyToDidKey(record.IssuerVerkey) : record.IssuerVerkey } }); }
/// <inheritdoc /> public virtual async Task RegisterNymAsync(IAgentContext context, string submitterDid, string theirDid, string theirVerkey, string role, TransactionCost paymentInfo = null) { if (DidUtils.IsFullVerkey(theirVerkey)) { theirVerkey = await Did.AbbreviateVerkeyAsync(theirDid, theirVerkey); } var req = await IndyLedger.BuildNymRequestAsync(submitterDid, theirDid, theirVerkey, null, role); var res = await SignAndSubmitAsync(context, submitterDid, req, paymentInfo); }
/// <inheritdoc /> public virtual async Task RegisterNymAsync(Wallet wallet, Pool pool, string submitterDid, string theirDid, string theirVerkey, string role) { if (DidUtils.IsFullVerkey(theirVerkey)) { theirVerkey = await Did.AbbreviateVerkeyAsync(theirDid, theirVerkey); } var req = await Ledger.BuildNymRequestAsync(submitterDid, theirDid, theirVerkey, null, role); var res = await Ledger.SignAndSubmitRequestAsync(pool, wallet, submitterDid, req); EnsureSuccessResponse(res); }
public async Task CanCreateInvitationWithDidKeyFormatAsync() { var connectionId = Guid.NewGuid().ToString(); var(msg, record) = await _connectionService.CreateInvitationAsync(_issuerWallet, new InviteConfiguration { ConnectionId = connectionId, UseDidKeyFormat = true }); var connection = await _connectionService.GetAsync(_issuerWallet, connectionId); Assert.True(DidUtils.IsDidKey(msg.RecipientKeys.First())); Assert.True(DidUtils.IsDidKey(msg.RoutingKeys.First())); Assert.False(connection.MultiPartyInvitation); Assert.Equal(ConnectionState.Invited, connection.State); Assert.Equal(connectionId, connection.Id); }
/// <inheritdoc/> public async Task <(DidExchangeRequestMessage, ConnectionRecord)> CreateRequestAsync(IAgentContext agentContext, string did) { var key = await Did.KeyForDidAsync(await agentContext.Pool, agentContext.Wallet, did); var endpointResult = await _ledgerService.LookupServiceEndpointAsync(agentContext, did); var myDid = await Did.CreateAndStoreMyDidAsync(agentContext.Wallet, "{}"); var connection = new ConnectionRecord { Endpoint = new AgentEndpoint { Uri = endpointResult.Result.Endpoint }, MyDid = DidUtils.ConvertVerkeyToDidKey(myDid.VerKey), MyVk = myDid.VerKey, TheirDid = did, TheirVk = key, State = ConnectionState.Negotiating, }; await _recordService.AddAsync(agentContext.Wallet, connection); var provisioningRecord = await _provisioningService.GetProvisioningAsync(agentContext.Wallet); var didDoc = new AttachmentContent { Base64 = connection.MyDidDoc(provisioningRecord).ToJson().ToBase64Url() }; await didDoc.SignWithJsonWebSignature(agentContext.Wallet, myDid.VerKey); var attachment = new Attachment { Id = Guid.NewGuid().ToString(), MimeType = "application/json", Data = didDoc }; var request = new DidExchangeRequestMessage { Did = connection.MyDid, Label = provisioningRecord.Owner.Name, DidDoc = attachment }; return(request, connection); }
/// <summary> /// Verify the json web signature of an attachment /// </summary> /// <param name="content">The attachment content to be verified.</param> /// <returns>True - signature is valid; False - signature is missing or invalid.</returns> public static async Task <bool> VerifyJsonWebSignature(this AttachmentContent content) { try { var did = content.JsonWebSignature.Header.Kid; var verkey = DidUtils.ConvertDidKeyToVerkey(did); var message = $"{content.JsonWebSignature.Protected}.{content.Base64}"; return(await Crypto.VerifyAsync(verkey, Encoding.ASCII.GetBytes(message), content.JsonWebSignature.Signature.GetBytesFromBase64())); } catch (Exception) { return(false); } }
/// <summary> /// Sign attachment content using json web signature /// </summary> /// <param name="content">The attachment content to be signed.</param> /// <param name="wallet">The wallet.</param> /// <param name="verkey">The verkey to be used for the signing.</param> /// <exception cref="NullReferenceException">Throws if payload is null.</exception> public static async Task SignWithJsonWebSignature(this AttachmentContent content, Wallet wallet, string verkey) { var payload = content.Base64; if (payload == null) { throw new NullReferenceException("No data to sign"); } var did = DidUtils.ConvertVerkeyToDidKey(verkey); var protectedHeader = new { alg = "EdDSA", kid = did, jwk = new { kty = "OKP", crv = "Ed25519", x = Multibase.Base58.Decode(verkey).ToBase64UrlString(), kid = did } }.ToJson().ToBase64Url(); var message = $"{protectedHeader}.{payload}"; var signature = (await Crypto.SignAsync(wallet, verkey, Encoding.ASCII.GetBytes(message))).ToBase64UrlString(); content.JsonWebSignature = new JsonWebSignature { Header = new JsonWebSignatureHeader { Kid = did }, Protected = protectedHeader, Signature = signature }; }
/// <inheritdoc /> public virtual async Task <(ConnectionInvitationMessage, ConnectionRecord)> CreateInvitationAsync(IAgentContext agentContext, InviteConfiguration config = null) { config = config ?? new InviteConfiguration(); var connection = new ConnectionRecord { Role = ConnectionRole.Inviter }; connection.Id = config.ConnectionId ?? connection.Id; Logger.LogInformation(LoggingEvents.CreateInvitation, "ConnectionId {0}", connection.Id); var connectionKey = await Crypto.CreateKeyAsync(agentContext.Wallet, "{}"); connection.SetTag(TagConstants.ConnectionKey, connectionKey); if (config.AutoAcceptConnection) { connection.SetTag(TagConstants.AutoAcceptConnection, "true"); } connection.MultiPartyInvitation = config.MultiPartyInvitation; if (!config.MultiPartyInvitation) { connection.Alias = config.TheirAlias; if (!string.IsNullOrEmpty(config.TheirAlias.Name)) { connection.SetTag(TagConstants.Alias, config.TheirAlias.Name); } } foreach (var tag in config.Tags) { connection.SetTag(tag.Key, tag.Value); } var provisioning = await ProvisioningService.GetProvisioningAsync(agentContext.Wallet); if (string.IsNullOrEmpty(provisioning.Endpoint.Uri)) { throw new AriesFrameworkException(ErrorCode.RecordInInvalidState, "Provision record has no endpoint information specified"); } await RecordService.AddAsync(agentContext.Wallet, connection); IList <string> routingKeys = null; if (provisioning.Endpoint.Verkey != null) { routingKeys = (config.UseDidKeyFormat ? provisioning.Endpoint.Verkey .Where(DidUtils.IsFullVerkey) .Select(DidUtils.ConvertVerkeyToDidKey) : provisioning.Endpoint.Verkey).ToList(); } string recipientKey = config.UseDidKeyFormat ? DidUtils.ConvertVerkeyToDidKey(connectionKey) : connectionKey; return(new ConnectionInvitationMessage(agentContext.UseMessageTypesHttps) { ServiceEndpoint = provisioning.Endpoint.Uri, RoutingKeys = routingKeys, RecipientKeys = new[] { recipientKey }, Label = config.MyAlias.Name ?? provisioning.Owner.Name, ImageUrl = config.MyAlias.ImageUrl ?? provisioning.Owner.ImageUrl }, connection); }
public void CanDetectVerkey() { Assert.True(DidUtils.IsVerkey(VALID_FULL_VERKEY)); Assert.True(DidUtils.IsVerkey(VALID_ABBREVIATED_VERKEY)); Assert.False(DidUtils.IsVerkey("")); }
public void CanDetectFullVerkey() { Assert.True(DidUtils.IsFullVerkey(VALID_FULL_VERKEY)); //Valid full verkey Assert.False(DidUtils.IsFullVerkey("")); Assert.False(DidUtils.IsFullVerkey(VALID_ABBREVIATED_VERKEY)); //Valid abbreviated verkey }
/// <inheritdoc/> public async Task <ConnectionRecord> ProcessRequestAsync(IAgentContext agentContext, DidExchangeRequestMessage requestMessage) { var myDid = await Did.CreateAndStoreMyDidAsync(agentContext.Wallet, "{}"); DidDoc didDoc = null; if (requestMessage.DidDoc.Data.Base64 is { } data) { var isValidSignature = await requestMessage.DidDoc.Data.VerifyJsonWebSignature(); if (isValidSignature == false) { throw new AriesFrameworkException(ErrorCode.InvalidSignatureEncoding, "The given JSON web signature is invalid"); } var json = data.FromBase64Url(); didDoc = json.ToObject <DidDoc>(); } // Todo: Handle resolvable Dids if (didDoc == null) { throw new NotImplementedException("Request message must provide an attached did document"); } if (didDoc.Keys.All(key => key.Type == DidDocExtensions.DefaultKeyType) == false) { throw new NotImplementedException($"Only {DidDocExtensions.DefaultKeyType} is supported"); } var indyService = (IndyAgentDidDocService)didDoc.Services.First(service => service is IndyAgentDidDocService); var agentEndpoint = new AgentEndpoint(indyService.ServiceEndpoint, null, indyService.RoutingKeys.ToArray()); var connectionRecord = new ConnectionRecord { Id = Guid.NewGuid().ToString(), Alias = new ConnectionAlias { Name = requestMessage.Label }, MyDid = DidUtils.ConvertVerkeyToDidKey(myDid.VerKey), MyVk = myDid.VerKey, TheirDid = requestMessage.Did, TheirVk = didDoc.Keys.FirstOrDefault(key => key.Controller == requestMessage.Did)?.PublicKeyBase58 ?? throw new NullReferenceException("Missing public for controller"), Endpoint = agentEndpoint, State = ConnectionState.Negotiating }; await _recordService.AddAsync(agentContext.Wallet, connectionRecord); _eventAggregator.Publish( new ServiceMessageProcessingEvent { MessageType = requestMessage.Type, RecordId = connectionRecord.Id, ThreadId = requestMessage.GetThreadId() }); return(connectionRecord); }
public void ConvertNonEd25519KeysToDidKeyWillThrowArgumentException() { Assert.Throws <ArgumentException>(() => DidUtils.ConvertDidKeyToVerkey(VALID_SECP256K1_0)); }
public void CanConvertVerkeyToDidKey() { var result = DidUtils.ConvertVerkeyToDidKey(ORIG_VERKEY); Assert.Equal(DERIVED_DID_KEY, result); }