Skip to content

Commit f3f9248

Browse files
author
Uwe Gradenegger
committed
Implementation of E-Mail and SMIME Capabilities
1 parent 341a3d0 commit f3f9248

3 files changed

Lines changed: 168 additions & 13 deletions

File tree

Functions/Get-NDESCertificate.ps1

Lines changed: 28 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,10 @@
2424
Specifies one or more User Principal Names to be written into the Subject Alternative Name (SAN) Extension of the Certificate Request.
2525
May be left Empty if you specify a Subject, DnsName or IP instead.
2626
27+
.PARAMETER Email
28+
Specifies one or more E-Mail addresses (RFC 822) to be written into the Subject Alternative Name (SAN) Extension of the Certificate Request.
29+
May be left Empty if you specify a Subject, DnsName, Upn or IP instead.
30+
2731
.PARAMETER IP
2832
Specifies or more IP Addresses to be written into the Subject Alternative Name (SAN) Extension of the Certificate Request.
2933
May be left Empty if you specify a Subject, DnsName or Upn instead.
@@ -100,6 +104,13 @@ Function Get-NDESCertificate {
100104
[mailaddress[]]
101105
$Upn,
102106

107+
[Parameter(ParameterSetName="NewRequest",Mandatory=$False)]
108+
[Alias("RFC822Name")]
109+
[Alias("E-Mail")]
110+
[ValidateNotNullOrEmpty()]
111+
[mailaddress[]]
112+
$Email,
113+
103114
[Alias("IPAddress")]
104115
[Parameter(Mandatory=$False)]
105116
[ValidateNotNullOrEmpty()]
@@ -268,7 +279,7 @@ Function Get-NDESCertificate {
268279

269280
# New Certificate Request
270281

271-
If ((-not $Dns) -and (-not $Upn) -and (-not $IP) -and ((-not $Subject) -or ($Subject -eq "CN="))) {
282+
If ((-not $Dns) -and (-not $Upn) -and (-not $Email) -and (-not $IP) -and ((-not $Subject) -or ($Subject -eq "CN="))) {
272283
Write-Error -Message "You must provide an Identity, either in Form ob a Subject or Subject Alternative Name!"
273284
return
274285
}
@@ -289,7 +300,7 @@ Function Get-NDESCertificate {
289300
}
290301

291302
# Set the Subject Alternative Names Extension if specified as Argument
292-
If ($Upn -or $Dns -or $IP) {
303+
If ($Upn -or $Email -or $Dns -or $IP) {
293304

294305
$SubjectAlternativeNamesExtension = New-Object -ComObject X509Enrollment.CX509ExtensionAlternativeNames
295306
$Sans = New-Object -ComObject X509Enrollment.CAlternativeNames
@@ -304,6 +315,19 @@ Function Get-NDESCertificate {
304315
$Entry
305316
)
306317
$Sans.Add($AlternativeNameObject)
318+
[void]([System.Runtime.Interopservices.Marshal]::ReleaseComObject($AlternativeNameObject))
319+
320+
}
321+
322+
Foreach ($Entry in $Email) {
323+
324+
$AlternativeNameObject = New-Object -ComObject X509Enrollment.CAlternativeName
325+
$AlternativeNameObject.InitializeFromString(
326+
$XCN_CERT_ALT_NAME_RFC822_NAME,
327+
$Entry
328+
)
329+
$Sans.Add($AlternativeNameObject)
330+
[void]([System.Runtime.Interopservices.Marshal]::ReleaseComObject($AlternativeNameObject))
307331

308332
}
309333

@@ -315,6 +339,7 @@ Function Get-NDESCertificate {
315339
$Entry
316340
)
317341
$Sans.Add($AlternativeNameObject)
342+
[void]([System.Runtime.Interopservices.Marshal]::ReleaseComObject($AlternativeNameObject))
318343

319344
}
320345

@@ -327,6 +352,7 @@ Function Get-NDESCertificate {
327352
[Convert]::ToBase64String($Entry.GetAddressBytes())
328353
)
329354
$Sans.Add($AlternativeNameObject)
355+
[void]([System.Runtime.Interopservices.Marshal]::ReleaseComObject($AlternativeNameObject))
330356

331357
}
332358

Functions/New-CertificateRequest.ps1

Lines changed: 92 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -20,15 +20,22 @@
2020
2121
.PARAMETER Dns
2222
Specifies one or more DNS Names to be written into the Subject Alternative Name (SAN) Extension of the Certificate Request.
23-
May be left Empty if you specify a Subject, Upn or IP instead.
23+
May be left Empty if you specify a Subject, Upn, Email or IP instead.
2424
2525
.PARAMETER Upn
2626
Specifies one or more User Principal Names to be written into the Subject Alternative Name (SAN) Extension of the Certificate Request.
27-
May be left Empty if you specify a Subject, DnsName or IP instead.
27+
May be left Empty if you specify a Subject, DnsName, Email or IP instead.
28+
29+
.PARAMETER Email
30+
Specifies one or more E-Mail addresses (RFC 822) to be written into the Subject Alternative Name (SAN) Extension of the Certificate Request.
31+
May be left Empty if you specify a Subject, DnsName, Upn or IP instead.
2832
2933
.PARAMETER IP
3034
Specifies or more IP Addresses to be written into the Subject Alternative Name (SAN) Extension of the Certificate Request.
31-
May be left Empty if you specify a Subject, DnsName or Upn instead.
35+
May be left Empty if you specify a Subject, DnsName, Email or Upn instead.
36+
37+
.PARAMETER Smime
38+
Specifies the S/MIME Capabilities the requestor supports.
3239
3340
.PARAMETER Aki
3441
Specifies the Authority Key Identifier Attribute to be included in the Request.
@@ -158,12 +165,43 @@ Function New-CertificateRequest {
158165
[mailaddress[]]
159166
$Upn,
160167

168+
[Alias("RFC822Name")]
169+
[Alias("E-Mail")]
170+
[Parameter(Mandatory=$False)]
171+
[ValidateNotNullOrEmpty()]
172+
[mailaddress[]]
173+
$Email,
174+
161175
[Alias("IPAddress")]
162176
[Parameter(Mandatory=$False)]
163177
[ValidateNotNullOrEmpty()]
164178
[System.Net.IPAddress[]]
165179
$IP,
166180

181+
[Alias("SmimeCapabilities")]
182+
[Parameter(Mandatory=$False)]
183+
[ValidateSet(
184+
"des",
185+
"des3",
186+
"rc2",
187+
"rc4",
188+
"des3wrap",
189+
"rc2wrap",
190+
"aes128",
191+
"aes192",
192+
"aes256",
193+
"aes128wrap",
194+
"aes192wrap",
195+
"aes256wrap",
196+
"md5",
197+
"sha1",
198+
"sha256",
199+
"sha384",
200+
"sha512"
201+
)]
202+
[String[]]
203+
$Smime,
204+
167205
[Alias("AuthorityKeyIdentifier")]
168206
[Parameter(Mandatory=$False)]
169207
[ValidatePattern("^[0-9a-fA-F]{40}$")]
@@ -286,7 +324,7 @@ Function New-CertificateRequest {
286324
}
287325
}
288326

289-
If ((-not $Dns) -and (-not $Upn) -and (-not $IP) -and ((-not $Subject) -or ($Subject -eq "CN="))) {
327+
If ((-not $Dns) -and (-not $Upn) -and (-not $Email) -and (-not $IP) -and ((-not $Subject) -or ($Subject -eq "CN="))) {
290328
Write-Error -Message "You must provide an Identity, either in Form ob a Subject or Subject Alternative Name!"
291329
return
292330
}
@@ -500,46 +538,60 @@ Function New-CertificateRequest {
500538
}
501539

502540
# Set the Subject Alternative Names Extension if specified as Argument
503-
If ($Upn -or $Dns -or $IP) {
541+
If ($Upn -or $Email -or $Dns -or $IP) {
504542

505543
# https://docs.microsoft.com/en-us/windows/win32/api/certenroll/nn-certenroll-ix509extensionalternativenames
506544
$SubjectAlternativeNamesExtension = New-Object -ComObject X509Enrollment.CX509ExtensionAlternativeNames
507545
$Sans = New-Object -ComObject X509Enrollment.CAlternativeNames
508546

547+
# https://msdn.microsoft.com/en-us/library/aa374981(VS.85).aspx
548+
509549
Foreach ($Entry in $Upn) {
510550

511-
# https://msdn.microsoft.com/en-us/library/aa374981(VS.85).aspx
512551
$AlternativeNameObject = New-Object -ComObject X509Enrollment.CAlternativeName
513552
$AlternativeNameObject.InitializeFromString(
514553
$XCN_CERT_ALT_NAME_USER_PRINCIPLE_NAME,
515554
$Entry
516555
)
517556
$Sans.Add($AlternativeNameObject)
557+
[void]([System.Runtime.Interopservices.Marshal]::ReleaseComObject($AlternativeNameObject))
558+
559+
}
560+
561+
Foreach ($Entry in $Email) {
562+
563+
$AlternativeNameObject = New-Object -ComObject X509Enrollment.CAlternativeName
564+
$AlternativeNameObject.InitializeFromString(
565+
$XCN_CERT_ALT_NAME_RFC822_NAME,
566+
$Entry
567+
)
568+
$Sans.Add($AlternativeNameObject)
569+
[void]([System.Runtime.Interopservices.Marshal]::ReleaseComObject($AlternativeNameObject))
518570

519571
}
520572

521573
Foreach ($Entry in $Dns) {
522574

523-
# https://msdn.microsoft.com/en-us/library/aa374981(VS.85).aspx
524575
$AlternativeNameObject = New-Object -ComObject X509Enrollment.CAlternativeName
525576
$AlternativeNameObject.InitializeFromString(
526577
$XCN_CERT_ALT_NAME_DNS_NAME,
527578
$Entry
528579
)
529580
$Sans.Add($AlternativeNameObject)
581+
[void]([System.Runtime.Interopservices.Marshal]::ReleaseComObject($AlternativeNameObject))
530582

531583
}
532584

533585
Foreach ($Entry in $IP) {
534586

535-
# https://msdn.microsoft.com/en-us/library/aa374981(VS.85).aspx
536587
$AlternativeNameObject = New-Object -ComObject X509Enrollment.CAlternativeName
537588
$AlternativeNameObject.InitializeFromRawData(
538589
$XCN_CERT_ALT_NAME_IP_ADDRESS,
539590
$XCN_CRYPT_STRING_BASE64,
540591
[Convert]::ToBase64String($Entry.GetAddressBytes())
541592
)
542593
$Sans.Add($AlternativeNameObject)
594+
[void]([System.Runtime.Interopservices.Marshal]::ReleaseComObject($AlternativeNameObject))
543595

544596
}
545597

@@ -550,6 +602,38 @@ Function New-CertificateRequest {
550602
$CertificateRequestObject.X509Extensions.Add($SubjectAlternativeNamesExtension)
551603

552604
}
605+
606+
# Set the S/MIME Capabilities Extension if specified as Argument
607+
If ($Smime) {
608+
609+
# https://docs.microsoft.com/en-us/windows/win32/api/certenroll/nn-certenroll-ix509extensionsmimecapabilities
610+
$SmimeExtension = New-Object -ComObject X509Enrollment.CX509ExtensionSmimeCapabilities
611+
612+
# https://docs.microsoft.com/en-us/windows/win32/api/certenroll/nn-certenroll-ismimecapabilities
613+
$SmimeCapabilitiesObject = New-Object -ComObject X509Enrollment.CSmimeCapabilities
614+
615+
$Smime | ForEach-Object -Process {
616+
617+
# The Bit length is only relevant for RC2 and RC4. We use the same defaults as Microsoft does.
618+
If ($_ -in ("rc2","rc2wrap","rc4")) { $BitCount = 128 } Else { $BitCount = 0 }
619+
620+
$OidObject = New-Object -ComObject X509Enrollment.CObjectId
621+
$OidObject.InitializeFromValue($SmimeCapabilityToOidTable[$_])
622+
623+
# https://docs.microsoft.com/en-us/windows/win32/api/certenroll/nf-certenroll-ismimecapability-initialize
624+
$SmimeCapabilityObject = New-Object -ComObject X509Enrollment.CSmimeCapability
625+
$SmimeCapabilityObject.Initialize(
626+
$OidObject,
627+
$BitCount
628+
)
629+
$SmimeCapabilitiesObject.Add($SmimeCapabilityObject)
630+
}
631+
632+
$SmimeExtension.InitializeEncode($SmimeCapabilitiesObject)
633+
634+
# Adding the Extension to the Certificate
635+
$CertificateRequestObject.X509Extensions.Add($SmimeExtension)
636+
}
553637

554638
# Set the Authority Key Identifier Extension if specified as Argument
555639
If ($Aki) {

PSCertificateEnrollment.psm1

Lines changed: 48 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@ New-Variable -Option Constant -Name XCN_CERT_NAME_STR_NONE -Value 0
5252
New-Variable -Option Constant -Name XCN_CERT_NAME_STR_FORCE_UTF8_DIR_STR_FLAG -Value 0x80000
5353
New-Variable -Option Constant -Name XCN_CERT_NAME_STR_DISABLE_UTF8_DIR_STR_FLAG -Value 0x100000
5454

55-
# https://blog.css-security.com/blog/creating-a-self-signed-ssl-certificate-using-powershell
55+
# https://docs.microsoft.com/en-us/windows/win32/api/certenroll/ne-certenroll-alternativenametype
5656
New-Variable -Option Constant -Name XCN_CERT_ALT_NAME_UNKNOWN -Value 0
5757
New-Variable -Option Constant -Name XCN_CERT_ALT_NAME_OTHER_NAME -Value 1
5858
New-Variable -Option Constant -Name XCN_CERT_ALT_NAME_RFC822_NAME -Value 2
@@ -107,6 +107,27 @@ New-Variable -Option Constant -Name XCN_OID_WHQL_CRYPTO -Value "1.3.6.1.4.1.311.
107107
New-Variable -Option Constant -Name XCN_OID_KP_KDC -Value "1.3.6.1.5.2.3.5"
108108
New-Variable -Option Constant -Name XCN_OID_KP_RDC -Value "1.3.6.1.4.1.311.54.1.2"
109109

110+
# https://docs.microsoft.com/en-us/windows/win32/api/certenroll/nn-certenroll-ix509extensionsmimecapabilities
111+
New-Variable -Option Constant -Name XCN_OID_OIWSEC_desCBC -Value "1.3.14.3.2.7"
112+
New-Variable -Option Constant -Name XCN_OID_RSA_DES_EDE3_CBC -Value "1.2.840.113549.3.7"
113+
New-Variable -Option Constant -Name XCN_OID_RSA_RC2CBC -Value "1.2.840.113549.3.2"
114+
New-Variable -Option Constant -Name XCN_OID_RSA_RC4 -Value "1.2.840.113549.3.4"
115+
New-Variable -Option Constant -Name XCN_OID_RSA_SMIMEalgCMS3DESwrap -Value "1.2.840.113549.1.9.16.3.6"
116+
New-Variable -Option Constant -Name XCN_OID_RSA_SMIMEalgCMSRC2wrap -Value "1.2.840.113549.1.9.16.3.7"
117+
New-Variable -Option Constant -Name XCN_OID_NIST_AES128_CBC -Value "2.16.840.1.101.3.4.1.2"
118+
New-Variable -Option Constant -Name XCN_OID_NIST_AES192_CBC -Value "2.16.840.1.101.3.4.1.22"
119+
New-Variable -Option Constant -Name XCN_OID_NIST_AES256_CBC -Value "2.16.840.1.101.3.4.1.42"
120+
New-Variable -Option Constant -Name XCN_OID_NIST_AES128_WRAP -Value "2.16.840.1.101.3.4.1.5"
121+
New-Variable -Option Constant -Name XCN_OID_NIST_AES192_WRAP -Value "2.16.840.1.101.3.4.1.25"
122+
New-Variable -Option Constant -Name XCN_OID_NIST_AES256_WRAP -Value "2.16.840.1.101.3.4.1.45"
123+
124+
# https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-gpnap/a48b02b2-2a10-4eb0-bed4-1807a6d2f5ad
125+
New-Variable -Option Constant -Name md5NoSign -Value "1.2.840.113549.2.5"
126+
New-Variable -Option Constant -Name sha1NoSign -Value "1.3.14.3.2.26"
127+
New-Variable -Option Constant -Name sha256NoSign -Value "2.16.840.1.101.3.4.2.1"
128+
New-Variable -Option Constant -Name sha384NoSign -Value "2.16.840.1.101.3.4.2.2"
129+
New-Variable -Option Constant -Name sha512NoSign -Value "2.16.840.1.101.3.4.2.3"
130+
110131
# https://msdn.microsoft.com/en-us/library/windows/desktop/aa374936(v=vs.85).aspx
111132
New-Variable -Option Constant -Name XCN_CRYPT_STRING_BASE64HEADER -Value 0
112133
New-Variable -Option Constant -Name XCN_CRYPT_STRING_BASE64 -Value 1
@@ -209,7 +230,7 @@ New-Variable -Option Constant -Name SCEPFailInfo -Value @(
209230
)
210231

211232
# https://msdn.microsoft.com/en-us/library/windows/desktop/aa378132(v=vs.85).aspx
212-
New-Variable -Option Constant EkuNameToOidTable -Value @{
233+
New-Variable -Option Constant -Name EkuNameToOidTable -Value @{
213234

214235
EnrollmentAgent = $XCN_OID_ENROLLMENT_AGENT
215236
ClientAuthentication = $XCN_OID_PKIX_KP_CLIENT_AUTH
@@ -233,6 +254,28 @@ New-Variable -Option Constant EkuNameToOidTable -Value @{
233254

234255
}
235256

257+
New-Variable -Option Constant -Name SmimeCapabilityToOidTable -Value @{
258+
259+
des = $XCN_OID_OIWSEC_desCBC
260+
des3 = $XCN_OID_RSA_DES_EDE3_CBC
261+
rc2 = $XCN_OID_RSA_RC2CBC
262+
rc4 = $XCN_OID_RSA_RC4
263+
des3wrap = $XCN_OID_RSA_SMIMEalgCMS3DESwrap
264+
rc2wrap = $XCN_OID_RSA_SMIMEalgCMSRC2wrap
265+
aes128 = $XCN_OID_NIST_AES128_CBC
266+
aes192 = $XCN_OID_NIST_AES192_CBC
267+
aes256 = $XCN_OID_NIST_AES256_CBC
268+
aes128wrap = $XCN_OID_NIST_AES128_WRAP
269+
aes192wrap = $XCN_OID_NIST_AES192_WRAP
270+
aes256wrap = $XCN_OID_NIST_AES256_WRAP
271+
md5 = $md5NoSign
272+
sha1 = $sha1NoSign
273+
sha256 = $sha256NoSign
274+
sha384 = $sha384NoSign
275+
sha512 = $sha512NoSign
276+
277+
}
278+
236279
$ModuleRoot = Split-Path -Path $MyInvocation.MyCommand.Definition -Parent
237280

238281
# Import Public Functions
@@ -248,4 +291,6 @@ $ModuleRoot = Split-Path -Path $MyInvocation.MyCommand.Definition -Parent
248291
. $ModuleRoot\Functions\Convert-StringToHex.ps1
249292
. $ModuleRoot\Functions\Get-Asn1LengthOctets.ps1
250293
. $ModuleRoot\Functions\New-AiaExtension.ps1
251-
. $ModuleRoot\Functions\New-CdpExtension.ps1
294+
. $ModuleRoot\Functions\New-CdpExtension.ps1
295+
296+
write-host $XCN_CERT_ALT_NAME_USER_PRINCIPLE_NAME

0 commit comments

Comments
 (0)