-
Notifications
You must be signed in to change notification settings - Fork 4.8k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[API Proposal]: Expose signature and protected headers raw bytes #72611
Comments
Tagging subscribers to this area: @dotnet/area-system-security, @vcsjones Issue DetailsBackground and motivationWe need to add APIs to expose the raw bytes of encoded protected headers and signatures in order to enable counter signature scenarios. API ProposalProposal: namespace System.Security.Cryptography.Cose
{
public abstract partial class CoseMessage
{
+ public ReadOnlyMemory<byte> EncodedProtectedHeaders { get { throw null; } }
}
public sealed partial class CoseSign1Message : CoseMessage
{
+ public ReadOnlyMemory<byte> Signature { get { throw null; } }
}
public sealed partial class CoseSignature
{
+ public ReadOnlyMemory<byte> EncodedProtectedHeaders { get { throw null; } }
+ public ReadOnlyMemory<byte> Signature { get { throw null; } }
}
} API UsageHere’s an example, it is quite cumbersome because countersigns are cumbersome, but please see byte[] CounterSign(byte[] encodedMsg)
{
CoseMultiSignMessage multiSignMsg = CoseMessage.DecodeMultiSign(encodedMsg);
CoseSignature signatureToCounterSign = multiSignMsg.Signatures[0];
byte[] encodedCounterSignature = GetCounterSign(multiSignMsg, signatureToCounterSign);
CoseHeaderLabel counterSignLabel = new(7);
CoseHeaderValue counterSignValue = CoseHeaderValue.FromEncodedValue(encodedCounterSignature);
signatureToCounterSign.UnprotectedHeaders.Add(counterSignLabel, counterSignValue);
return multiSignMsg.Encode();
}
private byte[] GetCounterSign(CoseMultiSignMessage msg, CoseSignature signature)
{
Assert.True(msg.Signatures.Contains(signature));
var writer = new CborWriter();
writer.WriteStartArray(3);
// encoded protected
byte[] encodedProtectedHeaders = GetCounterSignProtectedHeaders(-7 /*ES256*/);
writer.WriteByteString(encodedProtectedHeaders);
// empty unprotected headers
writer.WriteStartMap(0);
writer.WriteEndMap();
// signature
byte[] signatureBytes = GetSignature(MyEcdsaKey, MyHashAlgorithm, GetToBeSignedForCounterSign(msg, signature, encodedProtectedHeaders));
writer.WriteByteString(signatureBytes);
writer.WriteEndArray();
return writer.Encode();
}
private byte[] GetToBeSignedForCounterSign(CoseMultiSignMessage msg, CoseSignature signature, byte[] signProtected)
{
var writer = new CborWriter();
writer.WriteStartArray(5);
writer.WriteTextString("CounterSignature");
writer.WriteByteString(msg.EncodedProtectedHeaders.Span); // body_protected
writer.WriteByteString(signProtected); // sign_protected
writer.WriteByteString(default(Span<byte>)); // external_aad
writer.WriteByteString(signature.Signature.Span);
writer.WriteEndArray();
return writer.Encode();
}
private static byte[] GetCounterSignProtectedHeaders(int algorithm)
{
var writer = new CborWriter();
writer.WriteStartMap(1);
writer.WriteInt32(1); // alg
writer.WriteInt32(algorithm);
writer.WriteEndMap();
return writer.Encode();
}
private static byte[] GetSignature(AsymmetricAlgorithm key, HashAlgorithmName hash, byte[] toBeSigned)
{
if (key is ECDsa ecdsa)
{
return ecdsa.SignData(toBeSigned, hash);
}
else if (key is RSA rsa)
{
return rsa.SignData(toBeSigned, hash, RSASignaturePadding.Pss);
}
throw new ArgumentException("Key must be ECDsa or RSA", nameof(key));
} Alternative DesignsNo response RisksNone. As per the RFC, the raw bytes are part of the COSE_Sign* structure definition.
|
namespace System.Security.Cryptography.Cose;
public partial class CoseMessage
{
+ public ReadOnlyMemory<byte> RawProtectedHeaders { get; }
}
public partial class CoseSign1Message : CoseMessage
{
+ public ReadOnlyMemory<byte> Signature { get; }
}
public partial class CoseSignature
{
+ public ReadOnlyMemory<byte> RawProtectedHeaders { get; }
+ public ReadOnlyMemory<byte> Signature { get; }
} |
Background and motivation
We need to add APIs to expose the raw bytes of encoded protected headers and signatures in order to enable counter signature scenarios.
We don't directly support countersign as the spec defining them is still on draft, therefore, we want to allow them to at least be built without reflection.
API Proposal
Proposal:
API Usage
Here’s an example, it is quite cumbersome because countersigns are cumbersome, but please see
GetToBeSignedForCounterSign
which requires the aforementioned APIs to build the object that will be signed.Alternative Designs
No response
Risks
None. As per the RFC, the raw bytes are part of the COSE_Sign* structure definition.
Also, this change only applies to COSE_Sign*; COSE_Encrypt and other structures planned for the future won't be affected.
The text was updated successfully, but these errors were encountered: