Microsoft Virtualization Discussions

How to add subject alternates to New-NcSecurityCertificateCSR

jamesfort89
5,119 Views

When looking through this documentation, it doesn't describe how to put these in, but it lists the input as <DataONTAP.C.Types.SecurityCertificate.SubjectAlternatives>.  I don't see any documentation on this kind of input or how to generate it.

 

Without this, the signed certificates are worthless as they still trip the browser's warning that there's a problem with the certificate.  Is there any documentation on how to configure this parameter?

1 ACCEPTED SOLUTION

mbeattie
4,979 Views

Hi James,

 

I reached out to the developers internally for you and got an example of the CmdLet syntax to use. Can you please try this and let me know if that resolves the issue for you?

 

$a = New-Object DataONTAP.C.Types.SecurityCertificate.SubjectAlternatives
$a.Email = admin@testlab.local
$a.Dns = "svm1.testlab.local"
$a.Ip = "10.24.27.128"
$a.Uri = http://testlab.local
New-NcSecurityCertificateCsr -CommonName "C=US,O=NTAP,CN=test.testlab.local" -SubjectAlternatives $a

Modify variables to match your environment. Hope this helps

 

/Matt

If this post resolved your issue, help others by selecting ACCEPT AS SOLUTION or adding a KUDO.

View solution in original post

11 REPLIES 11

mbeattie
5,080 Views

Hi James,

 

You specify the Subject Alternative Names during the signing process. This can be done using the "certreq.exe" command. EG:

 

"certreq.exe -f -q -config ""$CertReqconfig"" –submit –attrib ""CertificateTemplate:$Template\nSAN:dns=$VserverName&dns=$fqdn$ipList"" ""$CsrPath.csr"" ""$SignedPath.cer"""

 

/Matt

If this post resolved your issue, help others by selecting ACCEPT AS SOLUTION or adding a KUDO.

jamesfort89
5,006 Views

That doesn't work for my environment.  I added the info into the certreq command, but it's ignored by the CA since the info isn't in the CSR to begin with.  I don't have control over the CA environment, so I need to be able to put the info inside the CSR when it's created.

mbeattie
4,996 Views

Hi James,

 

Have you considered invoking the REST API directly to ONTAP for creating the CSR instead of invoking the "New-NcSecurityCertificateCSR" CmdLet as the REST API POST method for "/security/certificate-signing-request" does enable the subject alternative name. EG:

 

 

{
  "_links": {},
  "algorithm": "rsa",
  "extended_key_usages": [
    "serverauth"
  ],
  "hash_function": "sha256",
  "key_usages": [
    "digitalsignature"
  ],
  "security_strength": 112,
  "subject_alternatives": {
    "dns": [
      "*.example.com"
    ],
    "email": [
      "abc@example.com"
    ],
    "ip": [
      "10.225.34.10"
    ],
    "uri": [
      "http://example.com"
    ]
  },
  "subject_name": "C=US,O=NTAP,CN=test.domain.com"
}

 

 

/Matt

If this post resolved your issue, help others by selecting ACCEPT AS SOLUTION or adding a KUDO.

mbeattie
4,980 Views

Hi James,

 

I reached out to the developers internally for you and got an example of the CmdLet syntax to use. Can you please try this and let me know if that resolves the issue for you?

 

$a = New-Object DataONTAP.C.Types.SecurityCertificate.SubjectAlternatives
$a.Email = admin@testlab.local
$a.Dns = "svm1.testlab.local"
$a.Ip = "10.24.27.128"
$a.Uri = http://testlab.local
New-NcSecurityCertificateCsr -CommonName "C=US,O=NTAP,CN=test.testlab.local" -SubjectAlternatives $a

Modify variables to match your environment. Hope this helps

 

/Matt

If this post resolved your issue, help others by selecting ACCEPT AS SOLUTION or adding a KUDO.

jamesfort89
4,970 Views

So, I did figure out the subjectalternates object with a little tinkering.  What was not clear was the structure of the common name. 

 

Also, I did find that all of the fields of the subject alternates needed to be filled out in order for it to work.  Otherwise, I got this error:

 

New-NcSecurityCertificateCsr : [400]: Certificate Authority requires a common name or one or more of the following SAN extensions: rfc822-name, uri, dns-name, ipaddr.

 

I did also find that it'll take just "CN=name.org.com" as the common name attribute.

 

This is what I needed though.  The command example given in the docs isn't updated to include this structure.  Thank you!

mbeattie
4,967 Views

Hi James,

 

Thanks for the feedback, I'll pass that onto to the developers. Looking at the Swagger UI for the REST API i would "assume" that all parameters for the Subject Alternative names should NOT be mandatory. You definitely don't need to provide all these parameters if using the certreq.exe for the certificate to be valid.

 

swagger.png

Good to hear it's finally working for you.

 

/Matt

If this post resolved your issue, help others by selecting ACCEPT AS SOLUTION or adding a KUDO.

jamesfort89
4,964 Views

Well, I do think I spoke a bit prematurely.  The certificate gets signed just fine with the CSR, but it's not returning the private key with the CSR.  So, I can't install the certificate back into the system.  Is there a hidden place that this is stored, or is this just a bug?

 

Code snippet:

PS C:\WINDOWS\system32> $csr_request

NcController    Csr                                                                                                                                                                           
------------    ---                                                                                                                                                                           
<name>          -----BEGIN CERTIFICATE REQUEST-----...

PS C:\WINDOWS\system32> $csr_request.PrivateKey

PS C:\WINDOWS\system32> $csr_request.PrivateKey += "test"

PS C:\WINDOWS\system32> $csr_request.PrivateKey
test

mbeattie
4,963 Views

Hi James,

 

The REST API does state "This API generates a Certificate Signing Request(CSR) and a private key pair" so i would expect it to output the private key (unless it's a bug).

 

What do you get if you run:

 

PS C:\> $csr_request | Format-List
PS C:\> $csr_request | Get-Member

 

/Matt

If this post resolved your issue, help others by selecting ACCEPT AS SOLUTION or adding a KUDO.

jamesfort89
4,962 Views

Here's what I get with those:

 

NcController : <scrubbed_name>
Csr          : -----BEGIN CERTIFICATE REQUEST-----
               <scrubbed>
               -----END CERTIFICATE REQUEST-----
               
PrivateKey   : 




PS C:\WINDOWS\system32> $csr_request | Get-Member


   TypeName: DataONTAP.C.Types.SecurityCertificate.CertificateSigningRequest

Name         MemberType Definition                                                
----         ---------- ----------                                                
Equals       Method     bool Equals(System.Object obj)                            
GetHashCode  Method     int GetHashCode()                                         
GetType      Method     type GetType()                                            
ToString     Method     string ToString()                                         
Csr          Property   string Csr {get;set;}                                     
NcController Property   NetApp.Ontapi.Filer.C.NcController NcController {get;set;}
PrivateKey   Property   string PrivateKey {get;set;}

The PrivateKey field is there, but it's just not getting populated when the data is returned.  Not sure if it's a bug with ONTAP or the PS toolkit.

mbeattie
4,912 Views

Hi James,

 

I am assuming this is a bug with the New-NcSecurityCertificateCsr CmdLet. I have raised this with the developers for you. In the interim as a workaround for you I've developed a Function Wrapper around the "security/certificate-signing-request" REST API for you. I've tested this and validated it does return the private key, also i've tested it to validate that the REST API does indeed not require all subject alternative fields (dns, email, ip, url). Please see the example code below:

 

Param(
   [Parameter(Mandatory = $True, HelpMessage = "The cluster name, FQDN or IP Address")]
   [ValidateNotNullOrEmpty()]
   [String]$Cluster,
   [Parameter(Mandatory = $False, HelpMessage = "The Asymmetric Encryption Algorithm")]
   [ValidateSet("rsa", "ecc")]
   [String]$Algorithm="rsa",
   [Parameter(Mandatory = $True, HelpMessage = "The extended key usage extension")]
   [ValidateSet("serverauth", "clientauth", "timestamping", "anyextendedkeyusage", "critical")]
   [Array]$ExtendedKeyUsage,
   [Parameter(Mandatory = $False, HelpMessage = "The Hashing function")]
   [ValidateSet("sha256", "sha224", "sha384", "sha512")]
   [String]$HashFunction="sha256",
   [Parameter(Mandatory = $True, HelpMessage = "The Key Usage")]
   [ValidateSet("digitalsignature", "nonrepudiation", "keyencipherment", "dataencipherment", "keyagreement", "keycertsign", "crlsign", "encipheronly", "decipheronly", "critica")]
   [Array]$KeyUsage,
   [Parameter(Mandatory = $False, HelpMessage = "The Security Strength")]
   [ValidateSet(112, 128, 192)]
   [Int]$SecurityStrength=112,
   [Parameter(Mandatory = $False, HelpMessage = "An Array of DNS names for Subject Alternate name extension")]
   [Array]$Dns,
   [Parameter(Mandatory = $False, HelpMessage = "An Array of Email Addresses for Subject Alternate name extension")]
   [Array]$EmailAddress,
   [Parameter(Mandatory = $False, HelpMessage = "An Array of IP Addresses for Subject Alternate name extension")]
   [Array]$IPAddress,
   [Parameter(Mandatory = $False, HelpMessage = "An Array of URL's for Subject Alternate name extension")]
   [Array]$Url,
   [Parameter(Mandatory = $True, HelpMessage = "The Subject Name. EG 'CN=engineering.netapp.com'")]
   [String]$SubjectName,
   [Parameter(Mandatory = $True, HelpMessage = "The Credential to authenticate to the cluster")]
   [ValidateNotNullOrEmpty()]
   [System.Management.Automation.PSCredential]$Credential
)
#'------------------------------------------------------------------------------
Function New-NcSecurityCsr{
   [CmdletBinding()]
   Param(
      [Parameter(Mandatory = $True, HelpMessage = "The cluster name, FQDN or IP Address")]
      [ValidateNotNullOrEmpty()]
      [String]$Cluster,
      [Parameter(Mandatory = $False, HelpMessage = "The Asymmetric Encryption Algorithm")]
      [ValidateSet("rsa", "ecc")]
      [String]$Algorithm="rsa",
      [Parameter(Mandatory = $True, HelpMessage = "The extended key usage extension")]
      [ValidateSet("serverauth", "clientauth", "timestamping", "anyextendedkeyusage", "critical")]
      [Array]$ExtendedKeyUsage,
      [Parameter(Mandatory = $False, HelpMessage = "The Hashing function")]
      [ValidateSet("sha256", "sha224", "sha384", "sha512")]
      [String]$HashFunction="sha256",
      [Parameter(Mandatory = $True, HelpMessage = "The Key Usage")]
      [ValidateSet("digitalsignature", "nonrepudiation", "keyencipherment", "dataencipherment", "keyagreement", "keycertsign", "crlsign", "encipheronly", "decipheronly", "critica")]
      [Array]$KeyUsage,
      [Parameter(Mandatory = $True, HelpMessage = "The Security Strength")]
      [ValidateSet(112, 128, 192)]
      [Int]$SecurityStrength,
      [Parameter(Mandatory = $False, HelpMessage = "An Array of DNS names for Subject Alternate name extension")]
      [Array]$Dns,
      [Parameter(Mandatory = $False, HelpMessage = "An Array of Email Addresses for Subject Alternate name extension")]
      [Array]$EmailAddress,
      [Parameter(Mandatory = $False, HelpMessage = "An Array of IP Addresses for Subject Alternate name extension")]
      [Array]$IPAddress,
      [Parameter(Mandatory = $False, HelpMessage = "An Array of URL's for Subject Alternate name extension")]
      [Array]$Url,
      [Parameter(Mandatory = $True, HelpMessage = "The Subject Name. EG 'CN=engineering.netapp.com'")]
      [String]$SubjectName,
      [Parameter(Mandatory = $True, HelpMessage = "The Credential to authenticate to the cluster")]
      [ValidateNotNullOrEmpty()]
      [System.Management.Automation.PSCredential]$Credential
   )
   #'---------------------------------------------------------------------------
   #'Set the authentication header to connect to AIQUM.
   #'---------------------------------------------------------------------------
   $auth    = [System.Convert]::ToBase64String([System.Text.Encoding]::UTF8.GetBytes($Credential.UserName + ':' + $Credential.GetNetworkCredential().Password))
   $headers = @{
      "Authorization" = "Basic $auth"
      "Accept"        = "application/json"
      "Content-Type"  = "application/json"
   }
   #'---------------------------------------------------------------------------
   #'Set the JSON body to create the CSR.
   #'---------------------------------------------------------------------------
   [String]$uri = "https://$Cluster/api/security/certificate-signing-request"
   $csr = @{};
   $csr.Add("algorithm", $Algorithm)
   $csr.Add("extended_key_usages", $ExtendedKeyUsage)
   $csr.Add("hash_function", $HashFunction)
   $csr.Add("key_usages", $KeyUsage)
   $csr.Add("security_strength", $SecurityStrength)
   $SubjectAlternatives = @{};
   $sa = $False
   If($Dns){
      $SubjectAlternatives.Add("dns", $Dns)
      $sa = $True
   }
   If($EmailAddress){
      $SubjectAlternatives.Add("email", $EmailAddress)
      $sa = $True
   }
   If($IPAddress){
      $SubjectAlternatives.Add("ip", $IPAddress)
      $sa = $True
   }
   If($Url){
      $SubjectAlternatives.Add("url", $Url)
      $sa = $True
   }
   If($sa){
      $csr.Add("subject_alternatives", $SubjectAlternatives)
   }
   $csr.Add("subject_name", $SubjectName)
   $body = $csr | ConvertTo-Json
   #'---------------------------------------------------------------------------
   #'Create the CSR.
   #'---------------------------------------------------------------------------
   Try{
      $response = Invoke-RestMethod -Uri $uri -Method POST -Body $body -Headers $headers -ErrorAction Stop
      Write-Host "Created CSR on cluster ""$Cluster"" using URI ""$uri"""
   }Catch{
      Write-Warning -Message $("Failed creating CSR on Cluster ""$Cluster"" using URI ""$uri"". Error " + $_.Exception.Message + ". Status Code " + $_.Exception.Response.StatusCode.value__)
   }
   Return $response;
}#'End Function New-NcSecurityCsr.
#'------------------------------------------------------------------------------
#'Set the command to create the CSR.
#'------------------------------------------------------------------------------
[String]$command = "New-NcSecurityCsr -Cluster $Cluster "
If($Algorithm){
   [String]$command += "-Algorithm $Algorithm "
}
If($ExtendedKeyUsage){
   [String]$command += "-ExtendedKeyUsage $ExtendedKeyUsage "
}
If($HashFunction){
   [String]$command += "-HashFunction $HashFunction "
}
[String]$command += "-KeyUsage $KeyUsage -SecurityStrength $SecurityStrength "
If($Dns){
   [String]$command += "-Dns $Dns "
}
If($EmailAddress){
   [String]$command += "-EmailAddress $EmailAddress "
}
If($IPAddress){
   [String]$command += "-IPAddress $IPAddress "
}
If($Url){
   [String]$command += "-Url $Url "
}
[String]$command += "-SubjectName $SubjectName -Credential `$Credential -ErrorAction Stop"
#'------------------------------------------------------------------------------
#'Create the CSR.
#'------------------------------------------------------------------------------
Try{
   $response = Invoke-Expression -Command $command -ErrorAction Stop
   Write-Host "Executed Command`: $command"
}Catch{
   Write-Warning -Message $("Failed Executing Command`: $command. Error " + $_.Exception.Message + ". Status Code " + $_.Exception.Response.StatusCode.value__)
   Break;
}
$response
$response | fl
#'------------------------------------------------------------------------------

 

Example output:

 

PS C:\Scripts\PowerShell\Projects\ONTAP\CreateSecurityCsr> .\CreateSecurityCsr.ps1 -Cluster cluster1.testlab.local -Algorithm rsa -ExtendedKeyUsage serverauth -HashFunction sha256 -KeyUsage digitalsignature -SecurityStrength 1
92 -Dns *.testlab.local -EmailAddress admin@testlab.local -IPAddress 192.168.100.100 -SubjectName CN=vserver1.testlab.local -Credential $credential
Created CSR on cluster "cluster1.testlab.local" using URI "https://cluster1.testlab.local/api/security/certificate-signing-request"
Executed Command: New-NcSecurityCsr -Cluster cluster1.testlab.local -Algorithm rsa -ExtendedKeyUsage serverauth -HashFunction sha256 -KeyUsage digitalsignature -SecurityStrength 192 -Dns *.testlab.local -EmailAddress admin@tes
tlab.local -IPAddress 192.168.100.100 -SubjectName CN=vserver1.testlab.local -Credential $Credential -ErrorAction Stop

csr
---
-----BEGIN CERTIFICATE REQUEST-----...




csr                   : -----BEGIN CERTIFICATE REQUEST-----
                        MIIE0zCCArsCAQAwITEfMB0GA1UEAxMWdnNlcnZlcjEudGVzdGxhYi5sb2NhbDCC
                        <redacted text>
                        nwUaiPwsVagdQOkhF2WpV6vscnvCO7tLgUMg5+1U1Fgbg4wP0fR4
                        -----END CERTIFICATE REQUEST-----

generated_private_key : -----BEGIN PRIVATE KEY-----
                        MIIJQQIBADANBgkqhkiG9w0BAQEFAASCCSswggknAgEAAoICAQCiPMoYhHDLR9vS
                        <redacted text>
                        DIgPtGqQrSP4LK1Lkp1JutmtJG6r
                        -----END PRIVATE KEY-----

 

Hope that helps until the issue is resolved?

 

/Matt

If this post resolved your issue, help others by selecting ACCEPT AS SOLUTION or adding a KUDO.

mbeattie
4,898 Views

Add this code to save the CSR and PrivateKey to files in the scripts working directory:

 

#'------------------------------------------------------------------------------
#'Save the CSR and Private Key for the SVM to files in the scripts working directory.
#'------------------------------------------------------------------------------
[String]$scriptPath = Split-Path($MyInvocation.MyCommand.Path)
[String]$svm = $SubjectName.Split(".")[0].Replace("CN=", "")
If($Null -ne $respone.csr){
   Try{
      New-Item -Path "$scriptPath\$svm.csr" -Type file -Value $response.csr -Force -ErrorAction Stop | Out-Null
   }Catch{
      Write-Warning -Message $("Failed creating CSR for vserver ""$svm"". Error " + $_.Exception.Message)
      Break;
   }
}Else{
   Write-Warning -Message "The CSR for vserver ""$svm"" is invalid"
   Break;
}
If($Null -ne $respone.generated_private_key){
   Try{
      New-Item -Path "$scriptPath\$svm.ppk" -Type file -Value $response.generated_private_key -Force -ErrorAction Stop | Out-Null
   }Catch{
      Write-Warning -Message $("Failed creating Private Key for vserver ""$svm"". Error " + $_.Exception.Message)
      Break;
   }
}Else{
   Write-Warning -Message "The Private Key for vserver ""$svm"" is invalid"
   Break;
}
#'------------------------------------------------------------------------------
If this post resolved your issue, help others by selecting ACCEPT AS SOLUTION or adding a KUDO.
Public