1 /*
2  * SPDX-FileCopyrightText: Copyright (c) 2023 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
3  * SPDX-License-Identifier: MIT
4  *
5  * Permission is hereby granted, free of charge, to any person obtaining a
6  * copy of this software and associated documentation files (the "Software"),
7  * to deal in the Software without restriction, including without limitation
8  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
9  * and/or sell copies of the Software, and to permit persons to whom the
10  * Software is furnished to do so, subject to the following conditions:
11  *
12  * The above copyright notice and this permission notice shall be included in
13  * all copies or substantial portions of the Software.
14  *
15  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
18  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
21  * DEALINGS IN THE SOFTWARE.
22  */
23 
24 /*!
25  * Provides the implementation for all GH100 SPDM certificate HAL interfaces.
26  */
27 
28 /* ------------------------ Includes --------------------------------------- */
29 #include "nvRmReg.h"
30 #include "gpu/spdm/spdm.h"
31 #include "gpu/spdm/libspdm_includes.h"
32 #include "spdm/rmspdmvendordef.h"
33 #include "flcnretval.h"
34 
35 /* ------------------------ Macros ----------------------------------------- */
36 #define DER_LONG_FORM_LENGTH_FIELD_BIT   (0x80)
37 #define DER_CERT_SIZE_FIELD_LENGTH       (0x4)
38 
39 #define SPDM_MAX_ENCODED_CERT_CHAIN_SIZE (0x1400)
40 
41 #define SPDM_PEM_BEGIN_CERTIFICATE "-----BEGIN CERTIFICATE-----\n"
42 #define SPDM_PEM_END_CERTIFICATE   "-----END CERTIFICATE-----\n"
43 
44 #define SPDM_L1_CERTIFICATE_PEM "-----BEGIN CERTIFICATE-----\n"\
45                                 "MIICCzCCAZCgAwIBAgIQLTZwscoQBBHB/sDoKgZbVDAKBggqhkjOPQQDAzA1MSIw\n"\
46                                 "IAYDVQQDDBlOVklESUEgRGV2aWNlIElkZW50aXR5IENBMQ8wDQYDVQQKDAZOVklE\n"\
47                                 "SUEwIBcNMjExMTA1MDAwMDAwWhgPOTk5OTEyMzEyMzU5NTlaMDUxIjAgBgNVBAMM\n"\
48                                 "GU5WSURJQSBEZXZpY2UgSWRlbnRpdHkgQ0ExDzANBgNVBAoMBk5WSURJQTB2MBAG\n"\
49                                 "ByqGSM49AgEGBSuBBAAiA2IABA5MFKM7+KViZljbQSlgfky/RRnEQScW9NDZF8SX\n"\
50                                 "gAW96r6u/Ve8ZggtcYpPi2BS4VFu6KfEIrhN6FcHG7WP05W+oM+hxj7nyA1r1jkB\n"\
51                                 "2Ry70YfThX3Ba1zOryOP+MJ9vaNjMGEwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8B\n"\
52                                 "Af8EBAMCAQYwHQYDVR0OBBYEFFeF/4PyY8xlfWi3Olv0jUrL+0lfMB8GA1UdIwQY\n"\
53                                 "MBaAFFeF/4PyY8xlfWi3Olv0jUrL+0lfMAoGCCqGSM49BAMDA2kAMGYCMQCPeFM3\n"\
54                                 "TASsKQVaT+8S0sO9u97PVGCpE9d/I42IT7k3UUOLSR/qvJynVOD1vQKVXf0CMQC+\n"\
55                                 "EY55WYoDBvs2wPAH1Gw4LbcwUN8QCff8bFmV4ZxjCRr4WXTLFHBKjbfneGSBWwA=\n"\
56                                 "-----END CERTIFICATE-----\n"
57 
58 #define SPDM_L2_CERTIFICATE_PEM "-----BEGIN CERTIFICATE-----\n"\
59                                 "MIICijCCAhCgAwIBAgIQTCVe3jvQAb8/SjtgX8qJijAKBggqhkjOPQQDAzA1MSIw\n"\
60                                 "IAYDVQQDDBlOVklESUEgRGV2aWNlIElkZW50aXR5IENBMQ8wDQYDVQQKDAZOVklE\n"\
61                                 "SUEwIBcNMjIwMTEyMDAwMDAwWhgPOTk5OTEyMzEyMzU5NTlaMD0xHjAcBgNVBAMM\n"\
62                                 "FU5WSURJQSBHSDEwMCBJZGVudGl0eTEbMBkGA1UECgwSTlZJRElBIENvcnBvcmF0\n"\
63                                 "aW9uMHYwEAYHKoZIzj0CAQYFK4EEACIDYgAE+pg+tDUuILlZILk5wg22YEJ9Oh6c\n"\
64                                 "yPcsv3IvgRWcV4LeZK1pTCoQDIplZ0E4qsLG3G04pxsbMhxbqkiz9pqlTV2rtuVg\n"\
65                                 "SmIqnSYkU1jWXsPS9oVLCGE8VRLl1JvqyOxUo4HaMIHXMA8GA1UdEwEB/wQFMAMB\n"\
66                                 "Af8wDgYDVR0PAQH/BAQDAgEGMDsGA1UdHwQ0MDIwMKAuoCyGKmh0dHA6Ly9jcmwu\n"\
67                                 "bmRpcy5udmlkaWEuY29tL2NybC9sMS1yb290LmNybDA3BggrBgEFBQcBAQQrMCkw\n"\
68                                 "JwYIKwYBBQUHMAGGG2h0dHA6Ly9vY3NwLm5kaXMubnZpZGlhLmNvbTAdBgNVHQ4E\n"\
69                                 "FgQUB0Kg6wOcgGB7oUFhmU2uJffCmx4wHwYDVR0jBBgwFoAUV4X/g/JjzGV9aLc6\n"\
70                                 "W/SNSsv7SV8wCgYIKoZIzj0EAwMDaAAwZQIxAPIQhnveFxYIrPzBqViT2I34SfS4\n"\
71                                 "JGWFnk/1UcdmgJmp+7l6rH/C4qxwntYSgeYrlQIwdjQuofHnhd1RL09OBO34566J\n"\
72                                 "C9bYAosT/86cCojiGjhLnal9hJOH0nS/lrbaoc5a\n"\
73                                 "-----END CERTIFICATE-----\n"
74 
75 #define SPDM_L3_CERTIFICATE_PEM "-----BEGIN CERTIFICATE-----\n"\
76                                 "MIICqjCCAi+gAwIBAgIQav5xhPkiMsjfeyQiYXduVjAKBggqhkjOPQQDAzA9MR4w\n"\
77                                 "HAYDVQQDDBVOVklESUEgR0gxMDAgSWRlbnRpdHkxGzAZBgNVBAoMEk5WSURJQSBD\n"\
78                                 "b3Jwb3JhdGlvbjAgFw0yMjAzMDEwMDAwMDBaGA85OTk5MTIzMTIzNTk1OVowUzEn\n"\
79                                 "MCUGA1UEAwweTlZJRElBIEdIMTAwIFByb3Zpc2lvbmVyIElDQSAxMRswGQYDVQQK\n"\
80                                 "DBJOVklESUEgQ29ycG9yYXRpb24xCzAJBgNVBAYTAlVTMHYwEAYHKoZIzj0CAQYF\n"\
81                                 "K4EEACIDYgAEzUdWqjn1OlXhLfFOKAFTghqG+Q3zF4xgSBbZsUEyWYCC3rKjE9Nn\n"\
82                                 "o88ZpBQx85Oo0PkqP2dwoMVNTQMv5cvy9jLaTvSTXZwN2HQHE9u7x7BIYrWi0sG3\n"\
83                                 "5q1IJNSOGO5Lo4HbMIHYMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEG\n"\
84                                 "MDwGA1UdHwQ1MDMwMaAvoC2GK2h0dHA6Ly9jcmwubmRpcy5udmlkaWEuY29tL2Ny\n"\
85                                 "bC9sMi1naDEwMC5jcmwwNwYIKwYBBQUHAQEEKzApMCcGCCsGAQUFBzABhhtodHRw\n"\
86                                 "Oi8vb2NzcC5uZGlzLm52aWRpYS5jb20wHQYDVR0OBBYEFCloyxYs0HeVcqJ5EAPm\n"\
87                                 "nroMzAqUMB8GA1UdIwQYMBaAFAdCoOsDnIBge6FBYZlNriX3wpseMAoGCCqGSM49\n"\
88                                 "BAMDA2kAMGYCMQDK0BCr49DNJ48Yh5wu388bZifDFxAsiUS4U1fGmpJZFhCbODH6\n"\
89                                 "mRwcMxp6EOayZuYCMQDYKTyNc2FxWFuhHtdCE3ls4S7SInehdErTZNuhFymc4YOM\n"\
90                                 "6VlLWTY/CM+resjjqxQ=\n"\
91                                 "-----END CERTIFICATE-----\n"
92 
93 const static NvU8 SPDM_L1_CERTIFICATE_DER[527] =
94 {
95     0x30, 0x82, 0x02, 0x0b, 0x30, 0x82, 0x01, 0x90, 0xa0, 0x03, 0x02, 0x01, 0x02, 0x02, 0x10, 0x2d,
96     0x36, 0x70, 0xb1, 0xca, 0x10, 0x04, 0x11, 0xc1, 0xfe, 0xc0, 0xe8, 0x2a, 0x06, 0x5b, 0x54, 0x30,
97     0x0a, 0x06, 0x08, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x04, 0x03, 0x03, 0x30, 0x35, 0x31, 0x22, 0x30,
98     0x20, 0x06, 0x03, 0x55, 0x04, 0x03, 0x0c, 0x19, 0x4e, 0x56, 0x49, 0x44, 0x49, 0x41, 0x20, 0x44,
99     0x65, 0x76, 0x69, 0x63, 0x65, 0x20, 0x49, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x20, 0x43,
100     0x41, 0x31, 0x0f, 0x30, 0x0d, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x0c, 0x06, 0x4e, 0x56, 0x49, 0x44,
101     0x49, 0x41, 0x30, 0x20, 0x17, 0x0d, 0x32, 0x31, 0x31, 0x31, 0x30, 0x35, 0x30, 0x30, 0x30, 0x30,
102     0x30, 0x30, 0x5a, 0x18, 0x0f, 0x39, 0x39, 0x39, 0x39, 0x31, 0x32, 0x33, 0x31, 0x32, 0x33, 0x35,
103     0x39, 0x35, 0x39, 0x5a, 0x30, 0x35, 0x31, 0x22, 0x30, 0x20, 0x06, 0x03, 0x55, 0x04, 0x03, 0x0c,
104     0x19, 0x4e, 0x56, 0x49, 0x44, 0x49, 0x41, 0x20, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x20, 0x49,
105     0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x20, 0x43, 0x41, 0x31, 0x0f, 0x30, 0x0d, 0x06, 0x03,
106     0x55, 0x04, 0x0a, 0x0c, 0x06, 0x4e, 0x56, 0x49, 0x44, 0x49, 0x41, 0x30, 0x76, 0x30, 0x10, 0x06,
107     0x07, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x02, 0x01, 0x06, 0x05, 0x2b, 0x81, 0x04, 0x00, 0x22, 0x03,
108     0x62, 0x00, 0x04, 0x0e, 0x4c, 0x14, 0xa3, 0x3b, 0xf8, 0xa5, 0x62, 0x66, 0x58, 0xdb, 0x41, 0x29,
109     0x60, 0x7e, 0x4c, 0xbf, 0x45, 0x19, 0xc4, 0x41, 0x27, 0x16, 0xf4, 0xd0, 0xd9, 0x17, 0xc4, 0x97,
110     0x80, 0x05, 0xbd, 0xea, 0xbe, 0xae, 0xfd, 0x57, 0xbc, 0x66, 0x08, 0x2d, 0x71, 0x8a, 0x4f, 0x8b,
111     0x60, 0x52, 0xe1, 0x51, 0x6e, 0xe8, 0xa7, 0xc4, 0x22, 0xb8, 0x4d, 0xe8, 0x57, 0x07, 0x1b, 0xb5,
112     0x8f, 0xd3, 0x95, 0xbe, 0xa0, 0xcf, 0xa1, 0xc6, 0x3e, 0xe7, 0xc8, 0x0d, 0x6b, 0xd6, 0x39, 0x01,
113     0xd9, 0x1c, 0xbb, 0xd1, 0x87, 0xd3, 0x85, 0x7d, 0xc1, 0x6b, 0x5c, 0xce, 0xaf, 0x23, 0x8f, 0xf8,
114     0xc2, 0x7d, 0xbd, 0xa3, 0x63, 0x30, 0x61, 0x30, 0x0f, 0x06, 0x03, 0x55, 0x1d, 0x13, 0x01, 0x01,
115     0xff, 0x04, 0x05, 0x30, 0x03, 0x01, 0x01, 0xff, 0x30, 0x0e, 0x06, 0x03, 0x55, 0x1d, 0x0f, 0x01,
116     0x01, 0xff, 0x04, 0x04, 0x03, 0x02, 0x01, 0x06, 0x30, 0x1d, 0x06, 0x03, 0x55, 0x1d, 0x0e, 0x04,
117     0x16, 0x04, 0x14, 0x57, 0x85, 0xff, 0x83, 0xf2, 0x63, 0xcc, 0x65, 0x7d, 0x68, 0xb7, 0x3a, 0x5b,
118     0xf4, 0x8d, 0x4a, 0xcb, 0xfb, 0x49, 0x5f, 0x30, 0x1f, 0x06, 0x03, 0x55, 0x1d, 0x23, 0x04, 0x18,
119     0x30, 0x16, 0x80, 0x14, 0x57, 0x85, 0xff, 0x83, 0xf2, 0x63, 0xcc, 0x65, 0x7d, 0x68, 0xb7, 0x3a,
120     0x5b, 0xf4, 0x8d, 0x4a, 0xcb, 0xfb, 0x49, 0x5f, 0x30, 0x0a, 0x06, 0x08, 0x2a, 0x86, 0x48, 0xce,
121     0x3d, 0x04, 0x03, 0x03, 0x03, 0x69, 0x00, 0x30, 0x66, 0x02, 0x31, 0x00, 0x8f, 0x78, 0x53, 0x37,
122     0x4c, 0x04, 0xac, 0x29, 0x05, 0x5a, 0x4f, 0xef, 0x12, 0xd2, 0xc3, 0xbd, 0xbb, 0xde, 0xcf, 0x54,
123     0x60, 0xa9, 0x13, 0xd7, 0x7f, 0x23, 0x8d, 0x88, 0x4f, 0xb9, 0x37, 0x51, 0x43, 0x8b, 0x49, 0x1f,
124     0xea, 0xbc, 0x9c, 0xa7, 0x54, 0xe0, 0xf5, 0xbd, 0x02, 0x95, 0x5d, 0xfd, 0x02, 0x31, 0x00, 0xbe,
125     0x11, 0x8e, 0x79, 0x59, 0x8a, 0x03, 0x06, 0xfb, 0x36, 0xc0, 0xf0, 0x07, 0xd4, 0x6c, 0x38, 0x2d,
126     0xb7, 0x30, 0x50, 0xdf, 0x10, 0x09, 0xf7, 0xfc, 0x6c, 0x59, 0x95, 0xe1, 0x9c, 0x63, 0x09, 0x1a,
127     0xf8, 0x59, 0x74, 0xcb, 0x14, 0x70, 0x4a, 0x8d, 0xb7, 0xe7, 0x78, 0x64, 0x81, 0x5b, 0x00
128 };
129 
130 const static NvU8 SPDM_L2_CERTIFICATE_DER[654] =
131 {
132     0x30, 0x82, 0x02, 0x8a, 0x30, 0x82, 0x02, 0x10, 0xa0, 0x03, 0x02, 0x01, 0x02, 0x02, 0x10, 0x4c,
133     0x25, 0x5e, 0xde, 0x3b, 0xd0, 0x01, 0xbf, 0x3f, 0x4a, 0x3b, 0x60, 0x5f, 0xca, 0x89, 0x8a, 0x30,
134     0x0a, 0x06, 0x08, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x04, 0x03, 0x03, 0x30, 0x35, 0x31, 0x22, 0x30,
135     0x20, 0x06, 0x03, 0x55, 0x04, 0x03, 0x0c, 0x19, 0x4e, 0x56, 0x49, 0x44, 0x49, 0x41, 0x20, 0x44,
136     0x65, 0x76, 0x69, 0x63, 0x65, 0x20, 0x49, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x20, 0x43,
137     0x41, 0x31, 0x0f, 0x30, 0x0d, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x0c, 0x06, 0x4e, 0x56, 0x49, 0x44,
138     0x49, 0x41, 0x30, 0x20, 0x17, 0x0d, 0x32, 0x32, 0x30, 0x31, 0x31, 0x32, 0x30, 0x30, 0x30, 0x30,
139     0x30, 0x30, 0x5a, 0x18, 0x0f, 0x39, 0x39, 0x39, 0x39, 0x31, 0x32, 0x33, 0x31, 0x32, 0x33, 0x35,
140     0x39, 0x35, 0x39, 0x5a, 0x30, 0x3d, 0x31, 0x1e, 0x30, 0x1c, 0x06, 0x03, 0x55, 0x04, 0x03, 0x0c,
141     0x15, 0x4e, 0x56, 0x49, 0x44, 0x49, 0x41, 0x20, 0x47, 0x48, 0x31, 0x30, 0x30, 0x20, 0x49, 0x64,
142     0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x31, 0x1b, 0x30, 0x19, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x0c,
143     0x12, 0x4e, 0x56, 0x49, 0x44, 0x49, 0x41, 0x20, 0x43, 0x6f, 0x72, 0x70, 0x6f, 0x72, 0x61, 0x74,
144     0x69, 0x6f, 0x6e, 0x30, 0x76, 0x30, 0x10, 0x06, 0x07, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x02, 0x01,
145     0x06, 0x05, 0x2b, 0x81, 0x04, 0x00, 0x22, 0x03, 0x62, 0x00, 0x04, 0xfa, 0x98, 0x3e, 0xb4, 0x35,
146     0x2e, 0x20, 0xb9, 0x59, 0x20, 0xb9, 0x39, 0xc2, 0x0d, 0xb6, 0x60, 0x42, 0x7d, 0x3a, 0x1e, 0x9c,
147     0xc8, 0xf7, 0x2c, 0xbf, 0x72, 0x2f, 0x81, 0x15, 0x9c, 0x57, 0x82, 0xde, 0x64, 0xad, 0x69, 0x4c,
148     0x2a, 0x10, 0x0c, 0x8a, 0x65, 0x67, 0x41, 0x38, 0xaa, 0xc2, 0xc6, 0xdc, 0x6d, 0x38, 0xa7, 0x1b,
149     0x1b, 0x32, 0x1c, 0x5b, 0xaa, 0x48, 0xb3, 0xf6, 0x9a, 0xa5, 0x4d, 0x5d, 0xab, 0xb6, 0xe5, 0x60,
150     0x4a, 0x62, 0x2a, 0x9d, 0x26, 0x24, 0x53, 0x58, 0xd6, 0x5e, 0xc3, 0xd2, 0xf6, 0x85, 0x4b, 0x08,
151     0x61, 0x3c, 0x55, 0x12, 0xe5, 0xd4, 0x9b, 0xea, 0xc8, 0xec, 0x54, 0xa3, 0x81, 0xda, 0x30, 0x81,
152     0xd7, 0x30, 0x0f, 0x06, 0x03, 0x55, 0x1d, 0x13, 0x01, 0x01, 0xff, 0x04, 0x05, 0x30, 0x03, 0x01,
153     0x01, 0xff, 0x30, 0x0e, 0x06, 0x03, 0x55, 0x1d, 0x0f, 0x01, 0x01, 0xff, 0x04, 0x04, 0x03, 0x02,
154     0x01, 0x06, 0x30, 0x3b, 0x06, 0x03, 0x55, 0x1d, 0x1f, 0x04, 0x34, 0x30, 0x32, 0x30, 0x30, 0xa0,
155     0x2e, 0xa0, 0x2c, 0x86, 0x2a, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x63, 0x72, 0x6c, 0x2e,
156     0x6e, 0x64, 0x69, 0x73, 0x2e, 0x6e, 0x76, 0x69, 0x64, 0x69, 0x61, 0x2e, 0x63, 0x6f, 0x6d, 0x2f,
157     0x63, 0x72, 0x6c, 0x2f, 0x6c, 0x31, 0x2d, 0x72, 0x6f, 0x6f, 0x74, 0x2e, 0x63, 0x72, 0x6c, 0x30,
158     0x37, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x01, 0x01, 0x04, 0x2b, 0x30, 0x29, 0x30,
159     0x27, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x30, 0x01, 0x86, 0x1b, 0x68, 0x74, 0x74,
160     0x70, 0x3a, 0x2f, 0x2f, 0x6f, 0x63, 0x73, 0x70, 0x2e, 0x6e, 0x64, 0x69, 0x73, 0x2e, 0x6e, 0x76,
161     0x69, 0x64, 0x69, 0x61, 0x2e, 0x63, 0x6f, 0x6d, 0x30, 0x1d, 0x06, 0x03, 0x55, 0x1d, 0x0e, 0x04,
162     0x16, 0x04, 0x14, 0x07, 0x42, 0xa0, 0xeb, 0x03, 0x9c, 0x80, 0x60, 0x7b, 0xa1, 0x41, 0x61, 0x99,
163     0x4d, 0xae, 0x25, 0xf7, 0xc2, 0x9b, 0x1e, 0x30, 0x1f, 0x06, 0x03, 0x55, 0x1d, 0x23, 0x04, 0x18,
164     0x30, 0x16, 0x80, 0x14, 0x57, 0x85, 0xff, 0x83, 0xf2, 0x63, 0xcc, 0x65, 0x7d, 0x68, 0xb7, 0x3a,
165     0x5b, 0xf4, 0x8d, 0x4a, 0xcb, 0xfb, 0x49, 0x5f, 0x30, 0x0a, 0x06, 0x08, 0x2a, 0x86, 0x48, 0xce,
166     0x3d, 0x04, 0x03, 0x03, 0x03, 0x68, 0x00, 0x30, 0x65, 0x02, 0x31, 0x00, 0xf2, 0x10, 0x86, 0x7b,
167     0xde, 0x17, 0x16, 0x08, 0xac, 0xfc, 0xc1, 0xa9, 0x58, 0x93, 0xd8, 0x8d, 0xf8, 0x49, 0xf4, 0xb8,
168     0x24, 0x65, 0x85, 0x9e, 0x4f, 0xf5, 0x51, 0xc7, 0x66, 0x80, 0x99, 0xa9, 0xfb, 0xb9, 0x7a, 0xac,
169     0x7f, 0xc2, 0xe2, 0xac, 0x70, 0x9e, 0xd6, 0x12, 0x81, 0xe6, 0x2b, 0x95, 0x02, 0x30, 0x76, 0x34,
170     0x2e, 0xa1, 0xf1, 0xe7, 0x85, 0xdd, 0x51, 0x2f, 0x4f, 0x4e, 0x04, 0xed, 0xf8, 0xe7, 0xae, 0x89,
171     0x0b, 0xd6, 0xd8, 0x02, 0x8b, 0x13, 0xff, 0xce, 0x9c, 0x0a, 0x88, 0xe2, 0x1a, 0x38, 0x4b, 0x9d,
172     0xa9, 0x7d, 0x84, 0x93, 0x87, 0xd2, 0x74, 0xbf, 0x96, 0xb6, 0xda, 0xa1, 0xce, 0x5a,
173 };
174 
175 const static NvU8 SPDM_L3_CERTIFICATE_DER[686] =
176 {
177     0x30, 0x82, 0x02, 0xaa, 0x30, 0x82, 0x02, 0x2f, 0xa0, 0x03, 0x02, 0x01, 0x02, 0x02, 0x10, 0x6a,
178     0xfe, 0x71, 0x84, 0xf9, 0x22, 0x32, 0xc8, 0xdf, 0x7b, 0x24, 0x22, 0x61, 0x77, 0x6e, 0x56, 0x30,
179     0x0a, 0x06, 0x08, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x04, 0x03, 0x03, 0x30, 0x3d, 0x31, 0x1e, 0x30,
180     0x1c, 0x06, 0x03, 0x55, 0x04, 0x03, 0x0c, 0x15, 0x4e, 0x56, 0x49, 0x44, 0x49, 0x41, 0x20, 0x47,
181     0x48, 0x31, 0x30, 0x30, 0x20, 0x49, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x31, 0x1b, 0x30,
182     0x19, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x0c, 0x12, 0x4e, 0x56, 0x49, 0x44, 0x49, 0x41, 0x20, 0x43,
183     0x6f, 0x72, 0x70, 0x6f, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x30, 0x20, 0x17, 0x0d, 0x32, 0x32,
184     0x30, 0x33, 0x30, 0x31, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x5a, 0x18, 0x0f, 0x39, 0x39, 0x39,
185     0x39, 0x31, 0x32, 0x33, 0x31, 0x32, 0x33, 0x35, 0x39, 0x35, 0x39, 0x5a, 0x30, 0x53, 0x31, 0x27,
186     0x30, 0x25, 0x06, 0x03, 0x55, 0x04, 0x03, 0x0c, 0x1e, 0x4e, 0x56, 0x49, 0x44, 0x49, 0x41, 0x20,
187     0x47, 0x48, 0x31, 0x30, 0x30, 0x20, 0x50, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x65,
188     0x72, 0x20, 0x49, 0x43, 0x41, 0x20, 0x31, 0x31, 0x1b, 0x30, 0x19, 0x06, 0x03, 0x55, 0x04, 0x0a,
189     0x0c, 0x12, 0x4e, 0x56, 0x49, 0x44, 0x49, 0x41, 0x20, 0x43, 0x6f, 0x72, 0x70, 0x6f, 0x72, 0x61,
190     0x74, 0x69, 0x6f, 0x6e, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x55,
191     0x53, 0x30, 0x76, 0x30, 0x10, 0x06, 0x07, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x02, 0x01, 0x06, 0x05,
192     0x2b, 0x81, 0x04, 0x00, 0x22, 0x03, 0x62, 0x00, 0x04, 0xcd, 0x47, 0x56, 0xaa, 0x39, 0xf5, 0x3a,
193     0x55, 0xe1, 0x2d, 0xf1, 0x4e, 0x28, 0x01, 0x53, 0x82, 0x1a, 0x86, 0xf9, 0x0d, 0xf3, 0x17, 0x8c,
194     0x60, 0x48, 0x16, 0xd9, 0xb1, 0x41, 0x32, 0x59, 0x80, 0x82, 0xde, 0xb2, 0xa3, 0x13, 0xd3, 0x67,
195     0xa3, 0xcf, 0x19, 0xa4, 0x14, 0x31, 0xf3, 0x93, 0xa8, 0xd0, 0xf9, 0x2a, 0x3f, 0x67, 0x70, 0xa0,
196     0xc5, 0x4d, 0x4d, 0x03, 0x2f, 0xe5, 0xcb, 0xf2, 0xf6, 0x32, 0xda, 0x4e, 0xf4, 0x93, 0x5d, 0x9c,
197     0x0d, 0xd8, 0x74, 0x07, 0x13, 0xdb, 0xbb, 0xc7, 0xb0, 0x48, 0x62, 0xb5, 0xa2, 0xd2, 0xc1, 0xb7,
198     0xe6, 0xad, 0x48, 0x24, 0xd4, 0x8e, 0x18, 0xee, 0x4b, 0xa3, 0x81, 0xdb, 0x30, 0x81, 0xd8, 0x30,
199     0x0f, 0x06, 0x03, 0x55, 0x1d, 0x13, 0x01, 0x01, 0xff, 0x04, 0x05, 0x30, 0x03, 0x01, 0x01, 0xff,
200     0x30, 0x0e, 0x06, 0x03, 0x55, 0x1d, 0x0f, 0x01, 0x01, 0xff, 0x04, 0x04, 0x03, 0x02, 0x01, 0x06,
201     0x30, 0x3c, 0x06, 0x03, 0x55, 0x1d, 0x1f, 0x04, 0x35, 0x30, 0x33, 0x30, 0x31, 0xa0, 0x2f, 0xa0,
202     0x2d, 0x86, 0x2b, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x63, 0x72, 0x6c, 0x2e, 0x6e, 0x64,
203     0x69, 0x73, 0x2e, 0x6e, 0x76, 0x69, 0x64, 0x69, 0x61, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x63, 0x72,
204     0x6c, 0x2f, 0x6c, 0x32, 0x2d, 0x67, 0x68, 0x31, 0x30, 0x30, 0x2e, 0x63, 0x72, 0x6c, 0x30, 0x37,
205     0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x01, 0x01, 0x04, 0x2b, 0x30, 0x29, 0x30, 0x27,
206     0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x30, 0x01, 0x86, 0x1b, 0x68, 0x74, 0x74, 0x70,
207     0x3a, 0x2f, 0x2f, 0x6f, 0x63, 0x73, 0x70, 0x2e, 0x6e, 0x64, 0x69, 0x73, 0x2e, 0x6e, 0x76, 0x69,
208     0x64, 0x69, 0x61, 0x2e, 0x63, 0x6f, 0x6d, 0x30, 0x1d, 0x06, 0x03, 0x55, 0x1d, 0x0e, 0x04, 0x16,
209     0x04, 0x14, 0x29, 0x68, 0xcb, 0x16, 0x2c, 0xd0, 0x77, 0x95, 0x72, 0xa2, 0x79, 0x10, 0x03, 0xe6,
210     0x9e, 0xba, 0x0c, 0xcc, 0x0a, 0x94, 0x30, 0x1f, 0x06, 0x03, 0x55, 0x1d, 0x23, 0x04, 0x18, 0x30,
211     0x16, 0x80, 0x14, 0x07, 0x42, 0xa0, 0xeb, 0x03, 0x9c, 0x80, 0x60, 0x7b, 0xa1, 0x41, 0x61, 0x99,
212     0x4d, 0xae, 0x25, 0xf7, 0xc2, 0x9b, 0x1e, 0x30, 0x0a, 0x06, 0x08, 0x2a, 0x86, 0x48, 0xce, 0x3d,
213     0x04, 0x03, 0x03, 0x03, 0x69, 0x00, 0x30, 0x66, 0x02, 0x31, 0x00, 0xca, 0xd0, 0x10, 0xab, 0xe3,
214     0xd0, 0xcd, 0x27, 0x8f, 0x18, 0x87, 0x9c, 0x2e, 0xdf, 0xcf, 0x1b, 0x66, 0x27, 0xc3, 0x17, 0x10,
215     0x2c, 0x89, 0x44, 0xb8, 0x53, 0x57, 0xc6, 0x9a, 0x92, 0x59, 0x16, 0x10, 0x9b, 0x38, 0x31, 0xfa,
216     0x99, 0x1c, 0x1c, 0x33, 0x1a, 0x7a, 0x10, 0xe6, 0xb2, 0x66, 0xe6, 0x02, 0x31, 0x00, 0xd8, 0x29,
217     0x3c, 0x8d, 0x73, 0x61, 0x71, 0x58, 0x5b, 0xa1, 0x1e, 0xd7, 0x42, 0x13, 0x79, 0x6c, 0xe1, 0x2e,
218     0xd2, 0x22, 0x77, 0xa1, 0x74, 0x4a, 0xd3, 0x64, 0xdb, 0xa1, 0x17, 0x29, 0x9c, 0xe1, 0x83, 0x8c,
219     0xe9, 0x59, 0x4b, 0x59, 0x36, 0x3f, 0x08, 0xcf, 0xab, 0x7a, 0xc8, 0xe3, 0xab, 0x14,
220 };
221 
222 /* ------------------------ Static Functions ------------------------------- */
223 /*!
224  @param pCert       : The pointer to certification chain start
225  @param bufferEnd   : The pointer to certification chain end
226  @parsm pCertLength : The pointer to store return certification size
227 
228  @return Return NV-OK if no error.
229 
230 * Static function that calculates the length of the X509 certificate in DER/TLV
231 * format. It assumes that the certificate is valid.
232 */
233 static NV_STATUS
234 _calcX509CertSize
235 (
236     NvU8 *pCert,
237     NvU8 *bufferEnd,
238     NvU32 *pCertLength
239 )
240 {
241     // The cert is in TLV format.
242     NvU32 certSize       = pCert[1];
243 
244     // Check to make sure that some data exists after SPDM header, and it is enough to check cert size.
245     if (pCert + DER_CERT_SIZE_FIELD_LENGTH >= bufferEnd ||
246         pCert + DER_CERT_SIZE_FIELD_LENGTH <= pCert)
247     {
248         NV_PRINTF(LEVEL_ERROR, " %s: pCert + DER_CERT_SIZE_FIELD_LENGTH(0x%x) is not valid value !! \n",
249                   __FUNCTION__, DER_CERT_SIZE_FIELD_LENGTH);
250 
251        return NV_ERR_BUFFER_TOO_SMALL;
252     }
253 
254     // Check if the length is in DER longform.
255     // MSB in the length field is set for long form notation.
256     // fields.
257     if (certSize & DER_LONG_FORM_LENGTH_FIELD_BIT)
258     {
259         //
260         // The remaining bits in the length field indicate the
261         // number of following bytes used to represent the length.
262         // in base 256, most significant digit first.
263         //
264         NvU32 numLenBytes = certSize & 0x3f;
265         NvU8 *pStart      = &pCert[2];
266         NvU8 *pEnd        = pStart + numLenBytes; // NOTE: Don't need to subtract numLenBytes 1 here.
267 
268         // Checking for buffer overflow.
269         if (pEnd > bufferEnd)
270         {
271             return NV_ERR_BUFFER_TOO_SMALL;
272         }
273 
274         certSize = *pStart;
275         while (++pStart < pEnd)
276         {
277             certSize = (certSize << 8) + *pStart ;
278         }
279         // Total cert length includes the Tag + length
280         // Adding it here.
281         certSize += 2 + numLenBytes;
282     }
283 
284     //
285     // Check to make sure we have not hit end of buffer, and there is space for AK cert.
286     // Check for underflow as well. This makes sure we haven't missed the calculation to
287     // go past the end of the buffer
288     //
289     if (pCert + (certSize - 1) > bufferEnd ||
290         pCert + (certSize - 1) <= pCert)
291     {
292         NV_PRINTF(LEVEL_ERROR, " %s: pCert + (certSize(0x%x) - 1) is not a valid value !! \n",
293                   __FUNCTION__, certSize);
294 
295         return NV_ERR_BUFFER_TOO_SMALL;
296     }
297 
298     *pCertLength = certSize;
299     return NV_OK;
300 }
301 
302 static NV_STATUS
303 pem_write_buffer
304 (
305     NvU8 const *der,
306     NvU64       derLen,
307     NvU8       *buffer,
308     NvU64       bufferLen,
309     NvU64      *bufferUsed
310 )
311 {
312     static const NvU8 base64[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
313     NvU64 i, tmp, size;
314     NvU64 printed = 0;
315     NvU8 *ptr = buffer;
316 
317     // Base64 encoded size
318     size = (derLen + 2) / 3 * 4;
319 
320     // Add 1 byte per 64 for newline
321     size = size + (size + 63) / 64;
322 
323     // Add header excluding the terminating null and footer including the null
324     size += sizeof(SPDM_PEM_BEGIN_CERTIFICATE) - 1 +
325             sizeof(SPDM_PEM_END_CERTIFICATE);
326 
327     if (bufferLen < size)
328     {
329         return NV_ERR_BUFFER_TOO_SMALL;
330     }
331 
332     portMemCopy(ptr, bufferLen - (ptr - buffer), SPDM_PEM_BEGIN_CERTIFICATE,
333                 sizeof(SPDM_PEM_BEGIN_CERTIFICATE) - 1);
334     ptr += sizeof(SPDM_PEM_BEGIN_CERTIFICATE) - 1;
335 
336     for (i = 0; (i + 2) < derLen; i += 3)
337     {
338         tmp = (der[i] << 16) | (der[i + 1] << 8) | (der[i + 2]);
339         *ptr++ = base64[(tmp >> 18) & 63];
340         *ptr++ = base64[(tmp >> 12) & 63];
341         *ptr++ = base64[(tmp >> 6) & 63];
342         *ptr++ = base64[(tmp >> 0) & 63];
343 
344         printed += 4;
345         if (printed == 64)
346         {
347             *ptr++ = '\n';
348             printed = 0;
349         }
350     }
351 
352     if ((i == derLen) && (printed != 0))
353     {
354         *ptr++ = '\n';
355     }
356 
357     // 1 byte extra
358     if (i == (derLen - 1))
359     {
360         tmp = der[i] << 4;
361         *ptr++ = base64[(tmp >> 6) & 63];
362         *ptr++ = base64[(tmp >> 0) & 63];
363         *ptr++ = '=';
364         *ptr++ = '=';
365         *ptr++ = '\n';
366     }
367 
368     // 2 byte extra
369     if (i == (derLen - 2))
370     {
371         tmp = ((der[i] << 8) | (der[i + 1])) << 2;
372         *ptr++ = base64[(tmp >> 12) & 63];
373         *ptr++ = base64[(tmp >> 6) & 63];
374         *ptr++ = base64[(tmp >> 0) & 63];
375         *ptr++ = '=';
376         *ptr++ = '\n';
377     }
378 
379      portMemCopy(ptr, bufferLen - (ptr - buffer), SPDM_PEM_END_CERTIFICATE,
380                  sizeof(SPDM_PEM_END_CERTIFICATE));
381      ptr += sizeof(SPDM_PEM_END_CERTIFICATE);
382 
383     *bufferUsed = size;
384     return NV_OK;
385 }
386 
387 /*!
388 * Static function builds the cert chain in DER format. It is assumed that
389 * the all the certificates are valid. Also it is assumed that there is a valid
390 * spdm session already established.
391 */
392 static NV_STATUS
393 _spdmBuildCertChainDer
394 (
395     NvU8   *pFirstCert,
396     NvU32   firstCertSize,
397     NvU8   *pSecondCert,
398     NvU32   secondCertSize,
399     NvU8   *pOutBuffer,
400     size_t *outBufferSize
401 )
402 {
403     NvU64      remainingOutBufferSize = 0;
404     NvU64      totalSize              = 0;
405     void      *pPortMemCopyStatus     = NULL;
406 
407     if (pFirstCert == NULL || pSecondCert == NULL || pOutBuffer == NULL || outBufferSize == NULL)
408     {
409         return NV_ERR_INVALID_ARGUMENT;
410     }
411 
412     // Calculate the total size of the certificate chain (in DER).
413     totalSize = sizeof(SPDM_L1_CERTIFICATE_DER) +
414                 sizeof(SPDM_L2_CERTIFICATE_DER) +
415                 sizeof(SPDM_L3_CERTIFICATE_DER) +
416                 secondCertSize                  +
417                 firstCertSize;
418 
419     remainingOutBufferSize = *outBufferSize;
420     if (remainingOutBufferSize < totalSize)
421     {
422         return NV_ERR_BUFFER_TOO_SMALL;
423     }
424 
425     //
426     // Write the L1 DER certificate to the output buffer
427     //
428     pPortMemCopyStatus = portMemCopy(pOutBuffer,
429                                      remainingOutBufferSize,
430                                      SPDM_L1_CERTIFICATE_DER,
431                                      sizeof(SPDM_L1_CERTIFICATE_DER));
432     if (pPortMemCopyStatus == NULL)
433     {
434         return NV_ERR_BUFFER_TOO_SMALL;
435     }
436 
437     remainingOutBufferSize -= sizeof(SPDM_L1_CERTIFICATE_DER);
438     pOutBuffer             += sizeof(SPDM_L1_CERTIFICATE_DER);
439 
440     //
441     // Write the L2 DER certificate to the output buffer
442     //
443     pPortMemCopyStatus = portMemCopy(pOutBuffer,
444                                      remainingOutBufferSize,
445                                      SPDM_L2_CERTIFICATE_DER,
446                                      sizeof(SPDM_L2_CERTIFICATE_DER));
447     if (pPortMemCopyStatus == NULL)
448     {
449         return NV_ERR_BUFFER_TOO_SMALL;
450     }
451 
452     remainingOutBufferSize -= sizeof(SPDM_L2_CERTIFICATE_DER);
453     pOutBuffer             += sizeof(SPDM_L2_CERTIFICATE_DER);
454 
455     //
456     // Write the L3 DER certificate to the output buffer
457     //
458     pPortMemCopyStatus = portMemCopy(pOutBuffer,
459                                      remainingOutBufferSize,
460                                      SPDM_L3_CERTIFICATE_DER,
461                                      sizeof(SPDM_L3_CERTIFICATE_DER));
462     if (pPortMemCopyStatus == NULL)
463     {
464         return NV_ERR_BUFFER_TOO_SMALL;
465     }
466 
467     remainingOutBufferSize -= sizeof(SPDM_L3_CERTIFICATE_DER);
468     pOutBuffer             += sizeof(SPDM_L3_CERTIFICATE_DER);
469 
470     //
471     // Write the IK certificate in DER to the output buffer
472     //
473     pPortMemCopyStatus = portMemCopy(pOutBuffer,
474                                      remainingOutBufferSize,
475                                      pSecondCert,
476                                      secondCertSize);
477     if (pPortMemCopyStatus == NULL)
478     {
479         return NV_ERR_BUFFER_TOO_SMALL;
480     }
481 
482     remainingOutBufferSize -= secondCertSize;
483     pOutBuffer             += secondCertSize;
484 
485     //
486     // Write the AK certificate in DER to the output buffer
487     //
488     pPortMemCopyStatus = portMemCopy(pOutBuffer,
489                                      remainingOutBufferSize,
490                                      pFirstCert,
491                                      firstCertSize);
492     if (pPortMemCopyStatus == NULL)
493     {
494         return NV_ERR_BUFFER_TOO_SMALL;
495     }
496 
497     remainingOutBufferSize -= firstCertSize;
498     pOutBuffer             += firstCertSize;
499 
500     // Output the total certificate chain size
501     *outBufferSize = totalSize;
502 
503     return NV_OK;
504 }
505 
506 /*!
507 * Static function that first converts the IK and AK certificates from DER to
508 * PEM format. Then it builds the cert chain in PEM format. It is assumed that
509 * the all the certificates are valid. Also it is assumed that there is a valid
510 * spdm session already established.
511 */
512 static NV_STATUS
513 _spdmBuildCertChainPem
514 (
515     NvU8   *pFirstCert,
516     NvU32   firstCertSize,
517     NvU8   *pSecondCert,
518     NvU32   secondCertSize,
519     NvU8   *pOutBuffer,
520     size_t *outBufferSize
521 )
522 {
523     NvU64              firstCertOutputSize      = 0;
524     NvU64              secondCertOutputSize     = 0;
525     NvU64              remainingOutBufferSize   = 0;
526     void              *pPortMemCopyStatus       = NULL;
527     NV_STATUS          status;
528 
529     if (pFirstCert == NULL || pSecondCert == NULL || pOutBuffer == NULL || outBufferSize == NULL)
530     {
531         return NV_ERR_INVALID_ARGUMENT;
532     }
533 
534     remainingOutBufferSize = *outBufferSize;
535 
536     //
537     // Write the AK certificate to the output buffer
538     //
539     status = pem_write_buffer(pFirstCert, firstCertSize, pOutBuffer,
540                               remainingOutBufferSize, &firstCertOutputSize);
541     if (status != NV_OK)
542     {
543         return status;
544     }
545 
546     //
547     // Keep track how much space we have left in the output buffer
548     // and where the next certificate should start.
549     // Clear the last byte (NULL).
550     //
551     remainingOutBufferSize -= firstCertOutputSize - 1;
552     pOutBuffer             += firstCertOutputSize - 1;
553 
554     //
555     // Write the IK certificate to the output buffer
556     //
557     status = pem_write_buffer(pSecondCert, secondCertSize, pOutBuffer,
558                               remainingOutBufferSize, &secondCertOutputSize);
559     if (status != NV_OK)
560     {
561         return status;
562     }
563 
564     remainingOutBufferSize -= secondCertOutputSize - 1;
565     pOutBuffer             += secondCertOutputSize - 1;
566 
567     // Checking if the available size of buffer is enough to keep the whole
568     // certificate chain otherwise raise error.
569     if (remainingOutBufferSize < sizeof(SPDM_L1_CERTIFICATE_PEM)
570                                + sizeof(SPDM_L2_CERTIFICATE_PEM)
571                                + sizeof(SPDM_L3_CERTIFICATE_PEM))
572     {
573         return NV_ERR_BUFFER_TOO_SMALL;
574     }
575 
576     //
577     // Write the L3 certificate to the output buffer
578     //
579     pPortMemCopyStatus = portMemCopy(pOutBuffer,
580                                      remainingOutBufferSize,
581                                      SPDM_L3_CERTIFICATE_PEM,
582                                      sizeof(SPDM_L3_CERTIFICATE_PEM) - 1);
583     if (pPortMemCopyStatus == NULL)
584     {
585         return NV_ERR_BUFFER_TOO_SMALL;
586     }
587 
588     remainingOutBufferSize -= sizeof(SPDM_L3_CERTIFICATE_PEM) - 1;
589     pOutBuffer             += sizeof(SPDM_L3_CERTIFICATE_PEM) - 1;
590 
591     //
592     // Write the L2 certificate to the output buffer
593     //
594     pPortMemCopyStatus = portMemCopy(pOutBuffer,
595                                      remainingOutBufferSize,
596                                      SPDM_L2_CERTIFICATE_PEM,
597                                      sizeof(SPDM_L2_CERTIFICATE_PEM) - 1);
598     if (pPortMemCopyStatus == NULL)
599     {
600         return NV_ERR_BUFFER_TOO_SMALL;
601     }
602     remainingOutBufferSize -= sizeof(SPDM_L2_CERTIFICATE_PEM) - 1;
603     pOutBuffer             += sizeof(SPDM_L2_CERTIFICATE_PEM) - 1;
604 
605     //
606     // Write the L1 certificate to the output buffer
607     //
608     pPortMemCopyStatus = portMemCopy(pOutBuffer,
609                                      remainingOutBufferSize,
610                                      SPDM_L1_CERTIFICATE_PEM,
611                                      sizeof(SPDM_L1_CERTIFICATE_PEM) - 1);
612     if (pPortMemCopyStatus == NULL)
613     {
614         return NV_ERR_BUFFER_TOO_SMALL;
615     }
616 
617     //
618     // Output the total certificate chain size
619     // Do not count the NULL bytes.
620     //
621     *outBufferSize = firstCertOutputSize - 1 +
622                      secondCertOutputSize - 1 +
623                      sizeof(SPDM_L3_CERTIFICATE_PEM) - 1 +
624                      sizeof(SPDM_L2_CERTIFICATE_PEM) - 1 +
625                      sizeof(SPDM_L1_CERTIFICATE_PEM) - 1;
626 
627     return NV_OK;
628 }
629 
630 /* ------------------------ Public Functions ------------------------------- */
631 NV_STATUS
632 spdmGetCertificates_GH100
633 (
634     OBJGPU *pGpu,
635     Spdm   *pSpdm
636 )
637 {
638     NV_STATUS          status = NV_OK;
639     NvU8              *pIkCertificate          = NULL;
640     NvU32              ikCertificateSize       = 0;
641     NvU8              *pAkCertificate          = NULL;
642     NvU32              akCertificateSize       = 0;
643     NvU8              *pGpuCerts               = NULL;
644     size_t             gpuCertsSize            = 0;
645     NvU8              *pDerCertChain           = NULL;
646     size_t             derCertChainSize        = 0;
647     NvU8              *pSpdmCertChainBufferEnd = NULL;
648     libspdm_context_t *pContext                = NULL;
649     uint32_t           base_hash_algo          = 0;
650     NvU32              totalSize               = 0;
651 
652     if (pGpu == NULL || pSpdm == NULL)
653     {
654         return NV_ERR_INVALID_ARGUMENT;
655     }
656 
657     if (pSpdm->pLibspdmContext == NULL)
658     {
659         return NV_ERR_NOT_READY;
660     }
661 
662     // Allocate buffer for certificates.
663     gpuCertsSize                    = LIBSPDM_MAX_CERT_CHAIN_SIZE;
664     pGpuCerts                       = portMemAllocNonPaged(gpuCertsSize);
665     derCertChainSize                = SPDM_MAX_ENCODED_CERT_CHAIN_SIZE;
666     pDerCertChain                   = portMemAllocNonPaged(derCertChainSize);
667     pSpdm->attestationCertChainSize = SPDM_MAX_ENCODED_CERT_CHAIN_SIZE;
668     pSpdm->pAttestationCertChain    = portMemAllocNonPaged(pSpdm->attestationCertChainSize);
669 
670     // Ensure data was properly allocated.
671     if (pGpuCerts == NULL || pDerCertChain == NULL || pSpdm->pAttestationCertChain == NULL)
672     {
673         status = NV_ERR_NO_MEMORY;
674         goto ErrorExit;
675     }
676 
677     portMemSet(pGpuCerts, 0, gpuCertsSize);
678     portMemSet(pDerCertChain, 0, derCertChainSize);
679     portMemSet(pSpdm->pAttestationCertChain, 0, pSpdm->attestationCertChainSize);
680 
681     // We fetch Attestation cert chain only on Hopper.
682     CHECK_SPDM_STATUS(libspdm_get_certificate(pSpdm->pLibspdmContext, SPDM_CERT_DEFAULT_SLOT_ID,
683                                               &gpuCertsSize, pGpuCerts));
684 
685     // Now, append the root certificates to create the entire chain.
686     pContext = (libspdm_context_t *)pSpdm->pLibspdmContext;
687 
688     //
689     // Skip over the certificate chain size, reserved size and the root hash
690     // pSpdmCertChainBufferEnd represents last valid byte for cert buffer.
691     //
692     pSpdmCertChainBufferEnd = pGpuCerts + gpuCertsSize - 1;
693     base_hash_algo          = pContext->connection_info.algorithm.base_hash_algo;
694     pIkCertificate          = (NvU8 *)pGpuCerts;
695     pIkCertificate         += sizeof(spdm_cert_chain_t) + libspdm_get_hash_size(base_hash_algo);
696 
697     // Calculate the size of the IK cert, and skip past it to get the AK cert.
698     status = _calcX509CertSize(pIkCertificate, pSpdmCertChainBufferEnd, &ikCertificateSize);
699 
700     if (status != NV_OK)
701     {
702         goto ErrorExit;
703     }
704 
705     pAkCertificate = (NvU8 *)pIkCertificate + ikCertificateSize;
706 
707     // Calculate the size of the AK certificate.
708     status = _calcX509CertSize(pAkCertificate, pSpdmCertChainBufferEnd, &akCertificateSize);
709     if (status != NV_OK)
710     {
711         return status;
712     }
713 
714     // Make sure we have calculated the size correctly.
715     if ((pAkCertificate + akCertificateSize - 1) != pSpdmCertChainBufferEnd)
716     {
717         return NV_ERR_BUFFER_TOO_SMALL;
718     }
719 
720     // Retrieve the entire certificate chain in DER format in order to validate it.
721     status = _spdmBuildCertChainDer(pAkCertificate, akCertificateSize,
722                                     pIkCertificate, ikCertificateSize,
723                                     pDerCertChain,
724                                     &derCertChainSize);
725 
726     if (status != NV_OK)
727     {
728         goto ErrorExit;
729     }
730 
731     totalSize = sizeof(SPDM_L1_CERTIFICATE_DER)  +
732                 sizeof(SPDM_L2_CERTIFICATE_DER)  +
733                 sizeof(SPDM_L3_CERTIFICATE_DER)  +
734                 akCertificateSize                +
735                 ikCertificateSize;
736 
737     if (derCertChainSize != totalSize)
738     {
739         NV_PRINTF(LEVEL_ERROR, " %s: derCertChainSize(%lu) != totalSize(0x%x) !! \n",
740                   __FUNCTION__, derCertChainSize, totalSize);
741 
742         // Something has gone quite wrong with our calculations.
743         status = NV_ERR_BUFFER_TOO_SMALL;
744         goto ErrorExit;
745     }
746 
747     // Now, validate that the certificate chain is correctly signed.
748     if (!libspdm_x509_verify_cert_chain(pDerCertChain, sizeof(SPDM_L1_CERTIFICATE_DER),
749                                         pDerCertChain + sizeof(SPDM_L1_CERTIFICATE_DER),
750                                         derCertChainSize - sizeof(SPDM_L1_CERTIFICATE_DER)))
751     {
752         status = NV_ERR_INVALID_DATA;
753         goto ErrorExit;
754     }
755 
756     //
757     // Now that the cert chain is valid, retrieve the cert chain in PEM format,
758     // as the Verifier can only parse PEM format.
759     //
760     status = _spdmBuildCertChainPem(pAkCertificate, akCertificateSize,
761                                     pIkCertificate, ikCertificateSize,
762                                     pSpdm->pAttestationCertChain,
763                                     &pSpdm->attestationCertChainSize);
764     if (status != NV_OK)
765     {
766         goto ErrorExit;
767     }
768 
769 ErrorExit:
770     //
771     // In both success and failure we need to free these allocated buffers.
772     // portMemFree() will handle if they are NULL. On success, keep
773     // the local pAttestationCertChain buffer.
774     //
775     portMemFree(pGpuCerts);
776     portMemFree(pDerCertChain);
777 
778     if (status != NV_OK)
779     {
780         // portMemFree() handles NULL.
781         portMemFree(pSpdm->pAttestationCertChain);
782         pSpdm->pAttestationCertChain    = NULL;
783         pSpdm->attestationCertChainSize = 0;
784     }
785 
786     return status;
787 }
788 
789 NV_STATUS
790 spdmGetCertChains_GH100
791 (
792     OBJGPU *pGpu,
793     Spdm   *pSpdm,
794     void   *pKeyExCertChain,
795     NvU32  *pKeyExCertChainSize,
796     void   *pAttestationCertChain,
797     NvU32  *pAttestationCertChainSize
798 )
799 {
800     if (pGpu == NULL || pSpdm == NULL || pAttestationCertChain == NULL ||
801         pAttestationCertChainSize == NULL)
802     {
803         return NV_ERR_INVALID_ARGUMENT;
804     }
805 
806     // Check that we're in a valid state.
807     if (pSpdm->pLibspdmContext == NULL || pSpdm->pAttestationCertChain == NULL ||
808         pSpdm->attestationCertChainSize == 0)
809     {
810         return NV_ERR_NOT_READY;
811     }
812 
813     // We only support Attestation certificates on Hopper.
814     if (pKeyExCertChainSize != NULL)
815     {
816         pKeyExCertChainSize = 0;
817     }
818 
819     if (*pAttestationCertChainSize < pSpdm->attestationCertChainSize)
820     {
821         return NV_ERR_BUFFER_TOO_SMALL;
822     }
823 
824     portMemCopy(pAttestationCertChain, *pAttestationCertChainSize,
825                 pSpdm->pAttestationCertChain, pSpdm->attestationCertChainSize);
826     *pAttestationCertChainSize = pSpdm->attestationCertChainSize;
827 
828     return NV_OK;
829 }
830