1- // Copyright 2025 Keyfactor
1+ // Copyright 2026 Keyfactor
22// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License.
33// You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
44// Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS,
55// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions
66// and limitations under the License.
77
88using System ;
9+ using System . Collections . Generic ;
910using System . Reflection ;
1011using System . IO ;
1112using System . Linq ;
@@ -285,8 +286,7 @@ public Constants.Keystore GetDefaultKeystore()
285286 /// <param name="keyType">Combination of key algorithm and key size</param>
286287 /// <param name="keystore">Default keystore for the device</param>
287288 /// <param name="subject">Subject provided for the certificate</param>
288- /// <param name="sans">Subject Alternative Names</param>
289- public void CreateSelfSignedCert ( string alias , string keyType , string keystore , string subject , string [ ] sans )
289+ public void CreateSelfSignedCert ( string alias , string keyType , string keystore , string subject )
290290 {
291291 try
292292 {
@@ -303,7 +303,7 @@ public void CreateSelfSignedCert(string alias, string keyType, string keystore,
303303 KeyType = keyType ,
304304 Keystore = keystore ,
305305 Subject = subject ,
306- SANS = sans ,
306+ SANS = [ ] ,
307307 ValidFrom = 0 , // Cert validity period will be determined by the template
308308 ValidTo = 0 // Cert validity period will be determined by the template
309309 }
@@ -347,25 +347,45 @@ public void CreateSelfSignedCert(string alias, string keyType, string keystore,
347347 }
348348
349349 /// <summary>
350- /// Obtains a CSR for the self-signed certificate with private key on the device.
351- /// Fields from the self-signed certificate will be copied into the CSR.
350+ /// Obtains a CSR for the self-signed or existing certificate with private key on the device.
351+ /// Fields from the certificate will be copied into the CSR.
352+ /// SANs will be added to the CSR.
352353 /// </summary>
353354 /// <param name="alias">Unique identifier for the cert to be generated from the CSR</param>
355+ /// <param name="subject">Subject provided for the certificate</param>
356+ /// <param name="sans">Subject Alternative Names</param>
354357 /// <returns>CSR string</returns>
355- public string ObtainCSR ( string alias )
358+ public string ObtainCSR ( string alias , string subject , List < string > sans )
356359 {
357360 try
358361 {
359362 Logger . MethodEntry ( ) ;
360363
361364 var postCSRResource = $ "{ Constants . RestApiEntryPoint } /certificates/{ alias } /get_csr";
362365
363- // Compose the body --- This is required, but leaving the contents blank .
364- // All information obtained in the self-signed cert will be used to create the CSR.
366+ // Compose the body --- This is required.
367+ // All information obtained in the self-signed or existing cert will be used to create the CSR.
365368 // If there are attributes assigned by the CA, those will override the attributes that end up
366369 // in the certificate signed by the CA.
367- string jsonBody = @"{""data"":{}}" ;
368- var httpResponse = ExecuteHttp ( postCSRResource , Method . Post , Constants . ApiType . Rest , jsonBody ) ;
370+ // 1. If a field is filled out, that value will be used in the CSR
371+ // 2. If a field is NOT filled out, the existing value from the existing certificate will be copied into the CSR
372+ // 3. If a field is filled out with a blank value, that field is not copied from the existing certificate nor added to the CSR
373+ var jsonBody = new StringBuilder ( @"{""data"":{" ) ;
374+
375+ if ( sans . Count == 0 )
376+ {
377+ jsonBody . Append ( @"""subject"":""" ) . Append ( subject ) . Append ( "}}" ) ;
378+ }
379+ else
380+ {
381+ jsonBody . Append ( @"""subject"":""" ) . Append ( subject ) . Append ( @""",""subject_alt_names"": [" ) ;
382+ string result = string . Join ( "," , sans ) ;
383+ jsonBody . Append ( result ) . Append ( "]}}" ) ;
384+ }
385+
386+ Logger . LogDebug ( $ "POST Request Body: { jsonBody } ") ;
387+
388+ var httpResponse = ExecuteHttp ( postCSRResource , Method . Post , Constants . ApiType . Rest , jsonBody . ToString ( ) ) ;
369389
370390 // Decode the HTTP response if failed
371391 if ( httpResponse is { IsSuccessful : false } )
0 commit comments