1
1
// Licensed to the .NET Foundation under one or more agreements.
2
2
// The .NET Foundation licenses this file to you under the MIT license.
3
3
4
+ using System . Buffers ;
5
+ using System . Diagnostics ;
4
6
using System . Formats . Cbor ;
7
+ using System . Runtime . InteropServices ;
5
8
using System . Runtime . Versioning ;
6
9
7
10
namespace System . Security . Cryptography . Cose
8
11
{
9
12
public abstract class CoseMessage
10
13
{
11
- internal const string PreviewFeatureMessage = "COSE is in preview." ;
12
14
private const byte EmptyStringByte = 0xa0 ;
15
+ internal const int SizeOfArrayOfFour = 1 ;
16
+
13
17
// COSE tags https://datatracker.ietf.org/doc/html/rfc8152#page-8 Table 1.
14
18
internal const CborTag Sign1Tag = ( CborTag ) 18 ;
15
19
@@ -46,19 +50,58 @@ public ReadOnlyMemory<byte>? Content
46
50
}
47
51
}
48
52
49
- public static CoseSign1Message DecodeSign1 ( byte [ ] cborPayload )
53
+ public static CoseSign1Message DecodeSign1 ( byte [ ] cborPayload ! ! )
54
+ => DecodeCoseSign1Core ( new CborReader ( cborPayload ) ) ;
55
+
56
+ public static CoseSign1Message DecodeSign1 ( ReadOnlySpan < byte > cborPayload )
57
+ {
58
+ unsafe
59
+ {
60
+ fixed ( byte * ptr = & MemoryMarshal . GetReference ( cborPayload ) )
61
+ {
62
+ using ( MemoryManager < byte > manager = new PointerMemoryManager < byte > ( ptr , cborPayload . Length ) )
63
+ {
64
+ return DecodeCoseSign1Core ( new CborReader ( manager . Memory ) ) ;
65
+ }
66
+ }
67
+ }
68
+ }
69
+
70
+ private static CoseSign1Message DecodeCoseSign1Core ( CborReader reader )
50
71
{
51
72
try
52
73
{
53
- var reader = new CborReader ( cborPayload ) ;
54
74
CborTag ? tag = DecodeTag ( reader ) ;
55
75
if ( tag != null && tag != Sign1Tag )
56
76
{
57
77
throw new CryptographicException ( SR . Format ( SR . DecodeSign1IncorrectTag , tag ) ) ;
58
78
}
59
79
60
- CoseSign1Message message = DecodeCoseSign1Core ( reader ) ;
61
- return reader . BytesRemaining == 0 ? message : throw new CryptographicException ( SR . Format ( SR . DecodeSign1ErrorWhileDecoding , SR . DecodeSign1MesageContainedTrailingData ) ) ;
80
+ int ? arrayLength = reader . ReadStartArray ( ) ;
81
+ if ( arrayLength != 4 )
82
+ {
83
+ throw new CryptographicException ( SR . Format ( SR . DecodeSign1ErrorWhileDecoding , SR . DecodeSign1ArrayLengthMustBeFour ) ) ;
84
+ }
85
+
86
+ var protectedHeader = new CoseHeaderMap ( ) ;
87
+ DecodeProtectedBucket ( reader , protectedHeader , out byte [ ] protectedHeaderAsBstr ) ;
88
+ protectedHeader . IsReadOnly = true ;
89
+
90
+ var unprotectedHeader = new CoseHeaderMap ( ) ;
91
+ DecodeUnprotectedBucket ( reader , unprotectedHeader ) ;
92
+
93
+ ThrowIfDuplicateLabels ( protectedHeader , unprotectedHeader ) ;
94
+
95
+ byte [ ] ? payload = DecodePayload ( reader ) ;
96
+ byte [ ] signature = DecodeSignature ( reader ) ;
97
+ reader . ReadEndArray ( ) ;
98
+
99
+ if ( reader . BytesRemaining != 0 )
100
+ {
101
+ throw new CryptographicException ( SR . Format ( SR . DecodeSign1ErrorWhileDecoding , SR . DecodeSign1MesageContainedTrailingData ) ) ;
102
+ }
103
+
104
+ return new CoseSign1Message ( protectedHeader , unprotectedHeader , payload , signature , protectedHeaderAsBstr ) ;
62
105
}
63
106
catch ( Exception ex ) when ( ex is CborContentException or InvalidOperationException )
64
107
{
@@ -75,30 +118,6 @@ public static CoseSign1Message DecodeSign1(byte[] cborPayload)
75
118
} ;
76
119
}
77
120
78
- private static CoseSign1Message DecodeCoseSign1Core ( CborReader reader )
79
- {
80
- int ? arrayLength = reader . ReadStartArray ( ) ;
81
- if ( arrayLength != 4 )
82
- {
83
- throw new CryptographicException ( SR . Format ( SR . DecodeSign1ErrorWhileDecoding , SR . DecodeSign1ArrayLengthMustBeFour ) ) ;
84
- }
85
-
86
- var protectedHeader = new CoseHeaderMap ( ) ;
87
- DecodeProtectedBucket ( reader , protectedHeader , out byte [ ] protectedHeaderAsBstr ) ;
88
- protectedHeader . IsReadOnly = true ;
89
-
90
- var unprotectedHeader = new CoseHeaderMap ( ) ;
91
- DecodeUnprotectedBucket ( reader , unprotectedHeader ) ;
92
-
93
- ThrowIfDuplicateLabels ( protectedHeader , unprotectedHeader ) ;
94
-
95
- byte [ ] ? payload = DecodePayload ( reader ) ;
96
- byte [ ] signature = DecodeSignature ( reader ) ;
97
- reader . ReadEndArray ( ) ;
98
-
99
- return new CoseSign1Message ( protectedHeader , unprotectedHeader , payload , signature , protectedHeaderAsBstr ) ;
100
- }
101
-
102
121
private static void DecodeProtectedBucket ( CborReader reader , CoseHeaderMap headerParameters , out byte [ ] protectedHeaderAsBstr )
103
122
{
104
123
protectedHeaderAsBstr = reader . ReadByteString ( ) ;
@@ -162,7 +181,7 @@ private static byte[] DecodeSignature(CborReader reader)
162
181
return reader . ReadByteString ( ) ;
163
182
}
164
183
165
- internal static byte [ ] CreateToBeSigned ( string context , ReadOnlySpan < byte > encodedProtectedHeader , ReadOnlySpan < byte > content )
184
+ internal static int CreateToBeSigned ( string context , ReadOnlySpan < byte > encodedProtectedHeader , ReadOnlySpan < byte > content , Span < byte > destination )
166
185
{
167
186
var writer = new CborWriter ( ) ;
168
187
writer . WriteStartArray ( 4 ) ;
@@ -171,9 +190,19 @@ internal static byte[] CreateToBeSigned(string context, ReadOnlySpan<byte> encod
171
190
writer . WriteByteString ( Span < byte > . Empty ) ; // external_aad
172
191
writer . WriteByteString ( content ) ; //payload or content
173
192
writer . WriteEndArray ( ) ;
174
- return writer . Encode ( ) ;
193
+ int bytesWritten = writer . Encode ( destination ) ;
194
+
195
+ Debug . Assert ( bytesWritten == writer . BytesWritten && bytesWritten == ComputeToBeSignedEncodedSize ( context , encodedProtectedHeader , content ) ) ;
196
+ return bytesWritten ;
175
197
}
176
198
199
+ internal static int ComputeToBeSignedEncodedSize ( string context , ReadOnlySpan < byte > encodedProtectedHeader , ReadOnlySpan < byte > content )
200
+ => SizeOfArrayOfFour +
201
+ CoseHelpers . GetTextStringEncodedSize ( context ) +
202
+ CoseHelpers . GetByteStringEncodedSize ( encodedProtectedHeader . Length ) +
203
+ CoseHelpers . GetByteStringEncodedSize ( Span < byte > . Empty . Length ) +
204
+ CoseHelpers . GetByteStringEncodedSize ( content . Length ) ;
205
+
177
206
// Validate duplicate labels https://datatracker.ietf.org/doc/html/rfc8152#section-3.
178
207
internal static void ThrowIfDuplicateLabels ( CoseHeaderMap ? protectedHeaders , CoseHeaderMap ? unprotectedHeaders )
179
208
{
0 commit comments