/// <summary> /// Verifies contents of list of relationships returned by the profile server against the expected list of cards. /// </summary> /// <param name="CardNumbers">Numbers of cards that are expected to be in the relationship list.</param> /// <param name="RelationshipList">Card list returned by the profile server.</param> /// <returns>true if the <paramref name="RelationshipList"/> contains cards specified by card numbers in <paramref name="CardNumbers"/>.</returns> public bool CheckRelationships(HashSet <int> CardNumbers, IEnumerable <IdentityRelationship> RelationshipList) { log.Trace("()"); bool error = false; bool[] cardsOk = new bool[SignedCards.Count]; foreach (IdentityRelationship relationship in RelationshipList) { CardApplicationInformation cardApplication = relationship.CardApplication; byte[] cardApplicationSignature = relationship.CardApplicationSignature.ToByteArray(); SignedRelationshipCard signedCard = relationship.Card; RelationshipCard card = signedCard.Card; byte[] cardId = card.CardId.ToByteArray(); int cardIndex = -1; for (int i = 0; i < SignedCards.Count; i++) { byte[] existingCardId = SignedCards[i].Card.CardId.ToByteArray(); if (!cardsOk[i] && (StructuralComparisons.StructuralComparer.Compare(existingCardId, cardId) == 0)) { cardIndex = i; break; } } if (cardIndex != -1) { if (CardNumbers.Contains(cardIndex + 1)) { byte[] issuerPublicKey = card.IssuerPublicKey.ToByteArray(); byte[] cardSignature = signedCard.IssuerSignature.ToByteArray(); bool cardSignatureOk = Ed25519.Verify(cardSignature, cardId, issuerPublicKey); bool cardContentOk = StructuralComparisons.StructuralComparer.Compare(SignedCards[cardIndex].ToByteArray(), signedCard.ToByteArray()) == 0; bool cardOk = cardSignatureOk && cardContentOk; byte[] recipientPublicKey = card.RecipientPublicKey.ToByteArray(); bool applicationSignatureOk = Ed25519.Verify(cardApplicationSignature, cardApplication.ToByteArray(), recipientPublicKey); bool applicationContentOk = StructuralComparisons.StructuralComparer.Compare(CardApplications[cardIndex].ToByteArray(), cardApplication.ToByteArray()) == 0; bool applicationOk = applicationSignatureOk && applicationContentOk; if (!cardOk) { log.Trace("Card index {0} is corrupted.", cardIndex + 1); error = true; break; } if (!applicationOk) { log.Trace("Card application ID '{0}' for card index {1} is corrupted.", Crypto.ToHex(cardApplication.ApplicationId.ToByteArray()), cardIndex + 1); error = true; break; } cardsOk[cardIndex] = true; } } else { log.Trace("Card ID '{0}' not recognized.", Crypto.ToHex(cardId)); error = true; break; } } foreach (int index in CardNumbers) { if (!cardsOk[index - 1]) { log.Trace("Card index {0} not retrieved.", index); error = true; break; } } bool res = !error; log.Trace("(-):{0}", res); return(res); }
/// <summary> /// Checks whether AddRelatedIdentityRequest request is valid. /// </summary> /// <param name="Client">Client that sent the request.</param> /// <param name="AddRelatedIdentityRequest">Client's request message to validate.</param> /// <param name="MessageBuilder">Client's network message builder.</param> /// <param name="RequestMessage">Full request message from client.</param> /// <param name="ErrorResponse">If the function fails, this is filled with error response message that is ready to be sent to the client.</param> /// <returns>true if the profile update request can be applied, false otherwise.</returns> public static bool ValidateAddRelatedIdentityRequest(IncomingClient Client, AddRelatedIdentityRequest AddRelatedIdentityRequest, PsMessageBuilder MessageBuilder, PsProtocolMessage RequestMessage, out PsProtocolMessage ErrorResponse) { log.Trace("()"); bool res = false; ErrorResponse = null; string details = null; if (AddRelatedIdentityRequest == null) { AddRelatedIdentityRequest = new AddRelatedIdentityRequest(); } if (AddRelatedIdentityRequest.CardApplication == null) { AddRelatedIdentityRequest.CardApplication = new CardApplicationInformation(); } if (AddRelatedIdentityRequest.SignedCard == null) { AddRelatedIdentityRequest.SignedCard = new SignedRelationshipCard(); } if (AddRelatedIdentityRequest.SignedCard.Card == null) { AddRelatedIdentityRequest.SignedCard.Card = new RelationshipCard(); } CardApplicationInformation cardApplication = AddRelatedIdentityRequest.CardApplication; SignedRelationshipCard signedCard = AddRelatedIdentityRequest.SignedCard; RelationshipCard card = signedCard.Card; byte[] applicationId = cardApplication.ApplicationId.ToByteArray(); byte[] cardId = card.CardId.ToByteArray(); if ((applicationId.Length == 0) || (applicationId.Length > RelatedIdentity.CardIdentifierLength)) { log.Debug("Card application ID is invalid."); details = "cardApplication.applicationId"; } if (details == null) { byte[] appCardId = cardApplication.CardId.ToByteArray(); if (!ByteArrayComparer.Equals(cardId, appCardId)) { log.Debug("Card IDs in application card and relationship card do not match."); details = "cardApplication.cardId"; } } if (details == null) { if (card.ValidFrom > card.ValidTo) { log.Debug("Card validFrom field is greater than validTo field."); details = "signedCard.card.validFrom"; } else { DateTime?cardValidFrom = ProtocolHelper.UnixTimestampMsToDateTime(card.ValidFrom); DateTime?cardValidTo = ProtocolHelper.UnixTimestampMsToDateTime(card.ValidTo); if (cardValidFrom == null) { log.Debug("Card validFrom value '{0}' is not a valid timestamp.", card.ValidFrom); details = "signedCard.card.validFrom"; } else if (cardValidTo == null) { log.Debug("Card validTo value '{0}' is not a valid timestamp.", card.ValidTo); details = "signedCard.card.validTo"; } } } if (details == null) { byte[] issuerPublicKey = card.IssuerPublicKey.ToByteArray(); bool pubKeyValid = (0 < issuerPublicKey.Length) && (issuerPublicKey.Length <= ProtocolHelper.MaxPublicKeyLengthBytes); if (!pubKeyValid) { log.Debug("Issuer public key has invalid length {0} bytes.", issuerPublicKey.Length); details = "signedCard.card.issuerPublicKey"; } } if (details == null) { byte[] recipientPublicKey = card.RecipientPublicKey.ToByteArray(); if (!ByteArrayComparer.Equals(recipientPublicKey, Client.PublicKey)) { log.Debug("Caller is not recipient of the card."); details = "signedCard.card.recipientPublicKey"; } } if (details == null) { if (!Client.MessageBuilder.VerifySignedConversationRequestBodyPart(RequestMessage, cardApplication.ToByteArray(), Client.PublicKey)) { log.Debug("Caller is not recipient of the card."); ErrorResponse = Client.MessageBuilder.CreateErrorInvalidSignatureResponse(RequestMessage); details = ""; } } if (details == null) { SemVer cardVersion = new SemVer(card.Version); if (!cardVersion.Equals(SemVer.V100)) { log.Debug("Card version is invalid or not supported."); details = "signedCard.card.version"; } } if (details == null) { if (Encoding.UTF8.GetByteCount(card.Type) > PsMessageBuilder.MaxRelationshipCardTypeLengthBytes) { log.Debug("Card type is too long."); details = "signedCard.card.type"; } } if (details == null) { RelationshipCard emptyIdCard = new RelationshipCard() { CardId = ProtocolHelper.ByteArrayToByteString(new byte[RelatedIdentity.CardIdentifierLength]), Version = card.Version, IssuerPublicKey = card.IssuerPublicKey, RecipientPublicKey = card.RecipientPublicKey, Type = card.Type, ValidFrom = card.ValidFrom, ValidTo = card.ValidTo }; byte[] hash = Crypto.Sha256(emptyIdCard.ToByteArray()); if (!ByteArrayComparer.Equals(hash, cardId)) { log.Debug("Card ID '{0}' does not match its hash '{1}'.", cardId.ToHex(64), hash.ToHex()); details = "signedCard.card.cardId"; } } if (details == null) { byte[] issuerSignature = signedCard.IssuerSignature.ToByteArray(); byte[] issuerPublicKey = card.IssuerPublicKey.ToByteArray(); if (!Ed25519.Verify(issuerSignature, cardId, issuerPublicKey)) { log.Debug("Issuer signature is invalid."); details = "signedCard.issuerSignature"; } } if (details == null) { res = true; } else { if (ErrorResponse == null) { ErrorResponse = MessageBuilder.CreateErrorInvalidValueResponse(RequestMessage, details); } } log.Trace("(-):{0}", res); return(res); }