private static bool IsRepositoryCounterSignerInfo(CRYPT_ATTRIBUTE_STRING commitmentTypeIndicationAttribute) { int sizeOfCryptIntegerBlob = MarshalUtility.SizeOf <CRYPT_INTEGER_BLOB>(); for (var i = 0; i < commitmentTypeIndicationAttribute.cValue; ++i) { var attributeValuePointer = new IntPtr( (long)commitmentTypeIndicationAttribute.rgValue + (i * sizeOfCryptIntegerBlob)); var attributeValue = MarshalUtility.PtrToStructure <CRYPT_INTEGER_BLOB>(attributeValuePointer); var bytes = new byte[attributeValue.cbData]; Marshal.Copy(attributeValue.pbData, bytes, startIndex: 0, length: bytes.Length); var commitmentTypeIndication = CommitmentTypeIndication.Read(bytes); if (string.Equals( commitmentTypeIndication.CommitmentTypeId.Value, Oids.CommitmentTypeIdentifierProofOfReceipt, StringComparison.Ordinal)) { return(true); } } return(false); }
private static bool IsRepositoryCounterSignerInfo(CMSG_SIGNER_INFO counterSignerInfo) { var signedAttributes = counterSignerInfo.AuthAttrs; int sizeOfCryptAttributeString = MarshalUtility.SizeOf <CRYPT_ATTRIBUTE_STRING>(); for (var i = 0; i < signedAttributes.cAttr; ++i) { var signedAttributePointer = new IntPtr( (long)signedAttributes.rgAttr + (i * sizeOfCryptAttributeString)); var signedAttribute = MarshalUtility.PtrToStructure <CRYPT_ATTRIBUTE_STRING>(signedAttributePointer); if (string.Equals(signedAttribute.pszObjId, Oids.CommitmentTypeIndication, StringComparison.Ordinal) && IsRepositoryCounterSignerInfo(signedAttribute)) { return(true); } } return(false); }
private unsafe RepositoryCounterSignerInfo?GetRepositoryCountersignature(HeapBlockRetainer retainer) { const uint primarySignerInfoIndex = 0; uint unsignedAttributeCount = 0; var pointer = IntPtr.Zero; NativeUtility.ThrowIfFailed(NativeMethods.CryptMsgGetParam( _handle, CMSG_GETPARAM_TYPE.CMSG_SIGNER_UNAUTH_ATTR_PARAM, primarySignerInfoIndex, pointer, ref unsignedAttributeCount)); if (unsignedAttributeCount == 0) { return(null); } pointer = retainer.Alloc((int)unsignedAttributeCount); NativeUtility.ThrowIfFailed(NativeMethods.CryptMsgGetParam( _handle, CMSG_GETPARAM_TYPE.CMSG_SIGNER_UNAUTH_ATTR_PARAM, primarySignerInfoIndex, pointer, ref unsignedAttributeCount)); var unsignedAttributes = MarshalUtility.PtrToStructure <CRYPT_ATTRIBUTES>(pointer); int sizeOfCryptAttributeString = MarshalUtility.SizeOf <CRYPT_ATTRIBUTE_STRING>(); int sizeOfCryptIntegerBlob = MarshalUtility.SizeOf <CRYPT_INTEGER_BLOB>(); for (uint i = 0; i < unsignedAttributes.cAttr; ++i) { var attributePointer = new IntPtr( (long)unsignedAttributes.rgAttr + (i * sizeOfCryptAttributeString)); var attribute = MarshalUtility.PtrToStructure <CRYPT_ATTRIBUTE_STRING>(attributePointer); if (!string.Equals(attribute.pszObjId, Oids.Countersignature, StringComparison.Ordinal)) { continue; } for (var j = 0; j < attribute.cValue; ++j) { var attributeValuePointer = new IntPtr( (long)attribute.rgValue + (j * sizeOfCryptIntegerBlob)); var attributeValue = MarshalUtility.PtrToStructure <CRYPT_INTEGER_BLOB>(attributeValuePointer); uint cbSignerInfo = 0; NativeUtility.ThrowIfFailed(NativeMethods.CryptDecodeObject( CMSG_ENCODING.Any, new IntPtr(NativeMethods.PKCS7_SIGNER_INFO), attributeValue.pbData, attributeValue.cbData, dwFlags: 0, pvStructInfo: IntPtr.Zero, pcbStructInfo: new IntPtr(&cbSignerInfo))); var counterSignerInfoPointer = retainer.Alloc((int)cbSignerInfo); NativeUtility.ThrowIfFailed(NativeMethods.CryptDecodeObject( CMSG_ENCODING.Any, new IntPtr(NativeMethods.PKCS7_SIGNER_INFO), attributeValue.pbData, attributeValue.cbData, dwFlags: 0, pvStructInfo: counterSignerInfoPointer, pcbStructInfo: new IntPtr(&cbSignerInfo))); var counterSignerInfo = MarshalUtility.PtrToStructure <CMSG_SIGNER_INFO>(counterSignerInfoPointer); if (IsRepositoryCounterSignerInfo(counterSignerInfo)) { return(new RepositoryCounterSignerInfo() { dwUnauthAttrIndex = i, UnauthAttr = attribute, SignerInfo = counterSignerInfo }); } } } return(null); }
internal unsafe void AddTimestampToRepositoryCountersignature(SignedCms timestamp) { using (var hb = new HeapBlockRetainer()) { var repositoryCountersignature = GetRepositoryCountersignature(hb); if (repositoryCountersignature == null) { throw new SignatureException(Strings.Error_NotOneRepositoryCounterSignature); } // Remove repository countersignature from message var countersignatureDelAttr = new CMSG_CTRL_DEL_SIGNER_UNAUTH_ATTR_PARA() { dwSignerIndex = 0, dwUnauthAttrIndex = repositoryCountersignature.Value.dwUnauthAttrIndex }; countersignatureDelAttr.cbSize = (uint)Marshal.SizeOf(countersignatureDelAttr); var unmanagedCountersignatureDelAttr = hb.Alloc(Marshal.SizeOf(countersignatureDelAttr)); Marshal.StructureToPtr(countersignatureDelAttr, unmanagedCountersignatureDelAttr, fDeleteOld: false); if (!NativeMethods.CryptMsgControl( _handle, dwFlags: 0, dwCtrlType: CMSG_CONTROL_TYPE.CMSG_CTRL_DEL_SIGNER_UNAUTH_ATTR, pvCtrlPara: unmanagedCountersignatureDelAttr)) { Marshal.ThrowExceptionForHR(Marshal.GetHRForLastWin32Error()); } // Add timestamp attribute to existing unsigned attributes var signerInfo = repositoryCountersignature.Value.SignerInfo; var unauthAttrCount = signerInfo.UnauthAttrs.cAttr + 1; var sizeOfCryptAttribute = MarshalUtility.SizeOf <CRYPT_ATTRIBUTE>(); var attributesArray = (CRYPT_ATTRIBUTE *)hb.Alloc((int)(sizeOfCryptAttribute * unauthAttrCount)); var currentAttribute = attributesArray; // Copy existing unsigned attributes for (var i = 0; i < unauthAttrCount - 1; ++i) { var existingAttributePointer = new IntPtr( (long)signerInfo.UnauthAttrs.rgAttr + (i * sizeOfCryptAttribute)); var existingAttribute = MarshalUtility.PtrToStructure <CRYPT_ATTRIBUTE>(existingAttributePointer); currentAttribute->pszObjId = existingAttribute.pszObjId; currentAttribute->cValue = existingAttribute.cValue; currentAttribute->rgValue = existingAttribute.rgValue; currentAttribute++; } // Add timestamp attribute *currentAttribute = GetCryptAttributeForData(timestamp.Encode(), Oids.SignatureTimeStampTokenAttribute, hb); signerInfo.UnauthAttrs = new CRYPT_ATTRIBUTES() { cAttr = unauthAttrCount, rgAttr = new IntPtr(attributesArray) }; // Encode signer info var unmanagedSignerInfo = hb.Alloc(Marshal.SizeOf(signerInfo)); Marshal.StructureToPtr(signerInfo, unmanagedSignerInfo, fDeleteOld: false); uint encodedLength = 0; if (!NativeMethods.CryptEncodeObjectEx( CMSG_ENCODING.Any, lpszStructType: new IntPtr(NativeMethods.PKCS7_SIGNER_INFO), pvStructInfo: unmanagedSignerInfo, dwFlags: 0, pEncodePara: IntPtr.Zero, pvEncoded: IntPtr.Zero, pcbEncoded: ref encodedLength)) { var err = Marshal.GetLastWin32Error(); if (err != NativeMethods.ERROR_MORE_DATA) { Marshal.ThrowExceptionForHR(NativeMethods.GetHRForWin32Error(err)); } } var unmanagedEncoded = hb.Alloc((int)encodedLength); if (!NativeMethods.CryptEncodeObjectEx( CMSG_ENCODING.Any, lpszStructType: new IntPtr(NativeMethods.PKCS7_SIGNER_INFO), pvStructInfo: unmanagedSignerInfo, dwFlags: 0, pEncodePara: IntPtr.Zero, pvEncoded: unmanagedEncoded, pcbEncoded: ref encodedLength)) { Marshal.ThrowExceptionForHR(Marshal.GetHRForLastWin32Error()); } var encondedSignerBlob = new CRYPT_INTEGER_BLOB() { cbData = encodedLength, pbData = unmanagedEncoded }; var unmanagedBlob = hb.Alloc(Marshal.SizeOf(encondedSignerBlob)); Marshal.StructureToPtr(encondedSignerBlob, unmanagedBlob, fDeleteOld: false); var signerInfoAttr = new CRYPT_ATTRIBUTE() { pszObjId = hb.AllocAsciiString(Oids.Countersignature), cValue = 1, rgValue = unmanagedBlob }; // Create add unauth for signer info var signerInfoAddAttr = CreateUnsignedAddAttribute(signerInfoAttr, hb); // Add repository countersignature back to message signerInfoAddAttr.cbSize = (uint)Marshal.SizeOf(signerInfoAddAttr); var unmanagedSignerInfoAddAttr = hb.Alloc(Marshal.SizeOf(signerInfoAddAttr)); Marshal.StructureToPtr(signerInfoAddAttr, unmanagedSignerInfoAddAttr, fDeleteOld: false); if (!NativeMethods.CryptMsgControl( _handle, dwFlags: 0, dwCtrlType: CMSG_CONTROL_TYPE.CMSG_CTRL_ADD_SIGNER_UNAUTH_ATTR, pvCtrlPara: unmanagedSignerInfoAddAttr)) { Marshal.ThrowExceptionForHR(Marshal.GetHRForLastWin32Error()); } } }
internal static SignedCms NativeSign(CmsSigner cmsSigner, byte[] data, CngKey privateKey) { using (var hb = new HeapBlockRetainer()) { var certificateBlobs = new BLOB[cmsSigner.Certificates.Count]; for (var i = 0; i < cmsSigner.Certificates.Count; ++i) { var cert = cmsSigner.Certificates[i]; var context = MarshalUtility.PtrToStructure <CERT_CONTEXT>(cert.Handle); certificateBlobs[i] = new BLOB() { cbData = context.cbCertEncoded, pbData = context.pbCertEncoded }; } byte[] encodedData; var signerInfo = CreateSignerInfo(cmsSigner, privateKey, hb); var signedInfo = new CMSG_SIGNED_ENCODE_INFO(); signedInfo.cbSize = Marshal.SizeOf(signedInfo); signedInfo.cSigners = 1; using (var signerInfoHandle = new SafeLocalAllocHandle(Marshal.AllocHGlobal(Marshal.SizeOf(signerInfo)))) { Marshal.StructureToPtr(signerInfo, signerInfoHandle.DangerousGetHandle(), fDeleteOld: false); signedInfo.rgSigners = signerInfoHandle.DangerousGetHandle(); signedInfo.cCertEncoded = certificateBlobs.Length; using (var certificatesHandle = new SafeLocalAllocHandle(Marshal.AllocHGlobal(Marshal.SizeOf(certificateBlobs[0]) * certificateBlobs.Length))) { for (var i = 0; i < certificateBlobs.Length; ++i) { Marshal.StructureToPtr(certificateBlobs[i], new IntPtr(certificatesHandle.DangerousGetHandle().ToInt64() + Marshal.SizeOf(certificateBlobs[i]) * i), fDeleteOld: false); } signedInfo.rgCertEncoded = certificatesHandle.DangerousGetHandle(); var hMsg = NativeMethods.CryptMsgOpenToEncode( CMSG_ENCODING.Any, dwFlags: 0, dwMsgType: NativeMethods.CMSG_SIGNED, pvMsgEncodeInfo: ref signedInfo, pszInnerContentObjID: null, pStreamInfo: IntPtr.Zero); ThrowIfFailed(!hMsg.IsInvalid); ThrowIfFailed(NativeMethods.CryptMsgUpdate( hMsg, data, (uint)data.Length, fFinal: true)); uint valueLength = 0; ThrowIfFailed(NativeMethods.CryptMsgGetParam( hMsg, CMSG_GETPARAM_TYPE.CMSG_CONTENT_PARAM, dwIndex: 0, pvData: null, pcbData: ref valueLength)); encodedData = new byte[(int)valueLength]; ThrowIfFailed(NativeMethods.CryptMsgGetParam( hMsg, CMSG_GETPARAM_TYPE.CMSG_CONTENT_PARAM, dwIndex: 0, pvData: encodedData, pcbData: ref valueLength)); } } var cms = new SignedCms(); cms.Decode(encodedData); return(cms); } }
internal unsafe static CMSG_SIGNER_ENCODE_INFO CreateSignerInfo( CmsSigner cmsSigner, CngKey privateKey, HeapBlockRetainer hb) { var signerInfo = new CMSG_SIGNER_ENCODE_INFO(); signerInfo.cbSize = (uint)Marshal.SizeOf(signerInfo); signerInfo.pCertInfo = MarshalUtility.PtrToStructure <CERT_CONTEXT>(cmsSigner.Certificate.Handle).pCertInfo; signerInfo.hCryptProvOrhNCryptKey = privateKey.Handle.DangerousGetHandle(); signerInfo.HashAlgorithm.pszObjId = cmsSigner.DigestAlgorithm.Value; if (cmsSigner.SignerIdentifierType == SubjectIdentifierType.SubjectKeyIdentifier) { var certContextHandle = IntPtr.Zero; try { certContextHandle = NativeMethods.CertDuplicateCertificateContext(cmsSigner.Certificate.Handle); uint cbData = 0; var pbData = IntPtr.Zero; ThrowIfFailed(NativeMethods.CertGetCertificateContextProperty( certContextHandle, NativeMethods.CERT_KEY_IDENTIFIER_PROP_ID, pbData, ref cbData)); if (cbData > 0) { pbData = hb.Alloc((int)cbData); ThrowIfFailed(NativeMethods.CertGetCertificateContextProperty( certContextHandle, NativeMethods.CERT_KEY_IDENTIFIER_PROP_ID, pbData, ref cbData)); signerInfo.SignerId.dwIdChoice = NativeMethods.CERT_ID_KEY_IDENTIFIER; signerInfo.SignerId.KeyId.cbData = cbData; signerInfo.SignerId.KeyId.pbData = pbData; } } finally { if (certContextHandle != IntPtr.Zero) { NativeMethods.CertFreeCertificateContext(certContextHandle); } } } if (cmsSigner.SignedAttributes.Count != 0) { signerInfo.cAuthAttr = cmsSigner.SignedAttributes.Count; checked { int sizeOfCryptAttribute = MarshalUtility.SizeOf <CRYPT_ATTRIBUTE>(); int sizeOfCryptIntegerBlob = MarshalUtility.SizeOf <CRYPT_INTEGER_BLOB>(); var attributesArray = (CRYPT_ATTRIBUTE *)hb.Alloc(sizeOfCryptAttribute * cmsSigner.SignedAttributes.Count); var currentAttribute = attributesArray; foreach (var attribute in cmsSigner.SignedAttributes) { currentAttribute->pszObjId = hb.AllocAsciiString(attribute.Oid.Value); currentAttribute->cValue = (uint)attribute.Values.Count; currentAttribute->rgValue = hb.Alloc(sizeOfCryptIntegerBlob); foreach (var value in attribute.Values) { var attrData = value.RawData; if (attrData.Length > 0) { var blob = (CRYPT_INTEGER_BLOB *)currentAttribute->rgValue; blob->cbData = (uint)attrData.Length; blob->pbData = hb.Alloc(value.RawData.Length); Marshal.Copy(attrData, 0, blob->pbData, attrData.Length); } } currentAttribute++; } signerInfo.rgAuthAttr = new IntPtr(attributesArray); } } return(signerInfo); }
private static void DispatchNativeEvent(ref NativeEvent nativeEvent) { switch (nativeEvent.EventType) { // Session case NativeMethods.Events.EventType.SessionStarted: _session.OnStarted(); break; case NativeMethods.Events.EventType.SessionDisconnected: _session.OnStopped(); break; case NativeMethods.Events.EventType.SessionPeerStateChanged: { var eventData = MarshalUtility.PtrToStructure <NativeMethods.Events.UMC_SessionPeerStateChangedEventData>(nativeEvent.EventData); PeerId peerId = new PeerId(eventData.PeerId); _session.OnPeerStateChanged(peerId, eventData.NewPeerState); break; } // Advertiser case NativeMethods.Events.EventType.AdvertiserInvitationReceived: { var eventData = MarshalUtility.PtrToStructure <NativeMethods.Events.UMC_AdvertiserInvitationReceivedEventData>(nativeEvent.EventData); PeerId peerId = new PeerId(eventData.PeerId); // The block is wrapped into an NSObject wrapper so that it can be GC'd and eventually released NSObject invitationHandlerBlock = new NSObject(eventData.InvitationHandler); InvitationHandler invitationHandlerAction = accept => { NativeMethods.AdvertiserInvitationHandlerBlock.Invoke(invitationHandlerBlock.NativePointer, accept, IntPtr.Zero); }; _customServiceAdvertiser.OnInvitationReceived(peerId, invitationHandlerAction); break; } case NativeMethods.Events.EventType.AdvertiserStartFailed: { var eventData = MarshalUtility.PtrToStructure <NativeMethods.Events.UMC_ErrorStringEventData>(nativeEvent.EventData); _customServiceAdvertiser.OnStartFailed(eventData.Error); break; } // Advertiser assistant case NativeMethods.Events.EventType.AdvertiserAssistantInvitationDismissed: _serviceAdvertiser.OnInvitationDismissed(); break; case NativeMethods.Events.EventType.AdvertiserAssistantInvitationPresenting: _serviceAdvertiser.OnInvitationPresenting(); break; // Peer discovery case NativeMethods.Events.EventType.NearbyServiceBrowserPeerFound: { var eventData = MarshalUtility.PtrToStructure <NativeMethods.Events.UMC_PeerFoundEventData>(nativeEvent.EventData); PeerId peerId = new PeerId(eventData.PeerId); Dictionary <string, string> discoveryInfo = eventData.DiscoveryInfoPairArray != IntPtr.Zero ? MarshalUtility.MarshalStringStringDictionary(eventData.DiscoveryInfoPairArray, eventData.DiscoveryInfoArrayPairCount) : null; _customPeerDiscovery.OnPeerFound(peerId, discoveryInfo); break; } case NativeMethods.Events.EventType.NearbyServiceBrowserPeerLost: { var eventData = MarshalUtility.PtrToStructure <NativeMethods.Events.UMC_NearbyServiceBrowserPeerLostEventData>(nativeEvent.EventData); PeerId peerId = new PeerId(eventData.PeerId); _customPeerDiscovery.OnPeerLost(peerId); break; } case NativeMethods.Events.EventType.NearbyServiceBrowserStartFailed: { var eventData = MarshalUtility.PtrToStructure <NativeMethods.Events.UMC_ErrorStringEventData>(nativeEvent.EventData); _customPeerDiscovery.OnStartFailed(eventData.Error); break; } // Peer discovery UI case NativeMethods.Events.EventType.BrowserViewControllerCancelled: _peerDiscovery.OnCancelled(); break; case NativeMethods.Events.EventType.BrowserViewControllerFinished: _peerDiscovery.OnFinished(); break; default: throw new InvalidEnumArgumentException("nativeEvent.EventType", (int)nativeEvent.EventType, typeof(NativeMethods.Events.EventType)); } }
private static void MessageHandler(NativeMethods.Events.EventType eventType, IntPtr eventDataPtr) { lock (_nativeEvents) { switch (eventType) { // Session case NativeMethods.Events.EventType.SessionStarted: case NativeMethods.Events.EventType.SessionDisconnected: case NativeMethods.Events.EventType.SessionPeerStateChanged: // Advertiser case NativeMethods.Events.EventType.AdvertiserInvitationReceived: case NativeMethods.Events.EventType.AdvertiserStartFailed: // Advertiser assistant case NativeMethods.Events.EventType.AdvertiserAssistantInvitationDismissed: case NativeMethods.Events.EventType.AdvertiserAssistantInvitationPresenting: // Peer discovery case NativeMethods.Events.EventType.NearbyServiceBrowserPeerFound: case NativeMethods.Events.EventType.NearbyServiceBrowserPeerLost: case NativeMethods.Events.EventType.NearbyServiceBrowserStartFailed: // Peer discovery UI case NativeMethods.Events.EventType.BrowserViewControllerCancelled: case NativeMethods.Events.EventType.BrowserViewControllerFinished: // Just store the event data, the event marshalling and invocation are deferred until we are on the main Unity thread _nativeEvents.Push(new NativeEvent(eventType, eventDataPtr)); return; case NativeMethods.Events.EventType.BrowserViewControllerNearbyPeerPresenting: { // Special event, can not defer, must be processed immediately var eventData = MarshalUtility.PtrToStructure <NativeMethods.Events.UMC_BrowserViewControllerNearbyPeerPresentingEventData>(eventDataPtr); PeerId peerId = new PeerId(eventData.PeerId); Dictionary <string, string> discoveryInfo = eventData.DiscoveryInfoPairArray != IntPtr.Zero ? MarshalUtility.MarshalStringStringDictionary(eventData.DiscoveryInfoPairArray, eventData.DiscoveryInfoArrayPairCount) : null; NativeMethods.Events.UMC_BrowserViewControllerNearbyPeerPresentingResultEventData result; result.ShouldPresent = true; _peerDiscovery.OnNearbyPeerPresenting(peerId, discoveryInfo, ref result.ShouldPresent); // Copy from managed to native Marshal.StructureToPtr(result, eventData.Result, false); // Event data is freed on the native side automatically after this method returns return; } // Logs case NativeMethods.Events.EventType.Log: { // Special event, logs can be logged at any time var eventData = MarshalUtility.PtrToStructure <NativeMethods.Events.UMC_LogEventData>(eventDataPtr); switch (eventData.Type) { case NativeMethods.LogType.Log: Debug.Log("[ALM] " + eventData.Text); break; case NativeMethods.LogType.Warning: Debug.LogWarning("[ALM] " + eventData.Text); break; case NativeMethods.LogType.Error: Debug.LogError("[ALM] " + eventData.Text); break; default: throw new ArgumentOutOfRangeException("eventData.Type"); } NativeMethods.Events.UMC_FreeEventData(eventType, eventDataPtr); return; } default: throw new ArgumentOutOfRangeException("eventType", eventType, null); } } }