Sample code for 30+ languages & platforms
PureBasic

Generate a CSR with keyUsage, extKeyUsage, and other Extensions

See more CSR Examples

Demonstrates how to generate a CSR containing a 1.2.840.113549.1.9.14 extensionRequest with the following extensions:
  • 1.3.6.1.4.1.311.20.2 enrollCerttypeExtension
  • 2.5.29.15 keyUsage
  • 2.5.29.37 extKeyUsage
  • 2.5.29.14 subjectKeyIdentifier

Chilkat PureBasic Downloads

PureBasic
IncludeFile "CkPublicKey.pb"
IncludeFile "CkBinData.pb"
IncludeFile "CkEcc.pb"
IncludeFile "CkPrivateKey.pb"
IncludeFile "CkPrng.pb"
IncludeFile "CkXml.pb"
IncludeFile "CkCsr.pb"

Procedure ChilkatExample()

    success.i = 0

    ; This requires the Chilkat API to have been previously unlocked.
    ; See Global Unlock Sample for sample code.

    ; This example will generate a secp256r1 ECDSA key for the CSR.
    ecc.i = CkEcc::ckCreate()
    If ecc.i = 0
        Debug "Failed to create object."
        ProcedureReturn
    EndIf

    prng.i = CkPrng::ckCreate()
    If prng.i = 0
        Debug "Failed to create object."
        ProcedureReturn
    EndIf

    privKey.i = CkPrivateKey::ckCreate()
    If privKey.i = 0
        Debug "Failed to create object."
        ProcedureReturn
    EndIf

    success = CkEcc::ckGenKey(ecc,"secp256r1",prng,privKey)
    If success = 0
        Debug "Failed to generate a new ECDSA private key."
        CkEcc::ckDispose(ecc)
        CkPrng::ckDispose(prng)
        CkPrivateKey::ckDispose(privKey)
        ProcedureReturn
    EndIf

    csr.i = CkCsr::ckCreate()
    If csr.i = 0
        Debug "Failed to create object."
        ProcedureReturn
    EndIf

    ; Add common CSR fields:
    CkCsr::setCkCommonName(csr, "mysubdomain.mydomain.com")
    CkCsr::setCkCountry(csr, "GB")
    CkCsr::setCkState(csr, "Yorks")
    CkCsr::setCkLocality(csr, "York")
    CkCsr::setCkCompany(csr, "Internet Widgits Pty Ltd")
    CkCsr::setCkEmailAddress(csr, "support@mydomain.com")

    ; Add the following 1.2.840.113549.1.9.14 extensionRequest
    ; Note: The easiest way to know the content and format of the XML to be added is to examine
    ; a pre-existing CSR with the same desired extensionRequest.  You can use Chilkat to
    ; get the extensionRequest from an existing CSR. 

    ; 
    ; Here is a sample extension request:

    ; <?xml version="1.0" encoding="utf-8"?>
    ; <set>
    ;     <sequence>
    ;         <sequence>
    ;             <oid>1.3.6.1.4.1.311.20.2</oid>
    ;             <asnOctets>
    ;                 <universal tag="30" constructed="0">AEUAbgBkAEUAbgB0AGkAdAB5AEMAbABpAGUAbgB0AEEAdQB0AGgAQwBlAHIAdABpAGYAaQBjAGEAdABl
    ; AF8AQwBTAFIAUABhAHMAcwB0AGgAcgBvAHUAZwBoAC8AVgAx</universal>
    ;             </asnOctets>
    ;         </sequence>
    ;         <sequence>
    ;             <oid>2.5.29.15</oid>
    ;             <bool>1</bool>
    ;             <asnOctets>
    ;                 <bits n="3">A0</bits>
    ;             </asnOctets>
    ;         </sequence>
    ;         <sequence>
    ;             <oid>2.5.29.37</oid>
    ;             <asnOctets>
    ;                 <sequence>
    ;                     <oid>1.3.6.1.5.5.7.3.3</oid>
    ;                 </sequence>
    ;             </asnOctets>
    ;         </sequence>
    ;         <sequence>
    ;             <oid>2.5.29.14</oid>
    ;             <asnOctets>
    ;                 <octets>MCzBMQAViXBz8IDt8LsgmJxJ4Xg=</octets>
    ;             </asnOctets>
    ;         </sequence>
    ;     </sequence>
    ; </set>

    ; Use this online tool to generate code from sample XML: 
    ; Generate Code to Create XML

    ; A few notes:
    ; The string "AEUAbgBkAEUAbgB0AGkAdAB5AEMAbABpAGUAbgB0AEEAdQB0AGgAQwBlAHIAdABpAGYAaQBjAGEAdABlAF8AQwBTAFIAUABhAHMAcwB0AGgAcgBvAHUAZwBoAC8AVgAx"
    ; is the base64 encoding of the utf-16be byte representation of the string "EndEntityClientAuthCertificate_CSRPassthrough/V1"

    s.s = "EndEntityClientAuthCertificate_CSRPassthrough/V1"
    bdTemp.i = CkBinData::ckCreate()
    If bdTemp.i = 0
        Debug "Failed to create object."
        ProcedureReturn
    EndIf

    CkBinData::ckAppendString(bdTemp,s,"utf-16be")
    s_base64_utf16be.s = CkBinData::ckGetEncoded(bdTemp,"base64")
    ; The string should be "AEUA....."
    Debug s_base64_utf16be

    ; Here's the code to generate the above extension request.

    xml.i = CkXml::ckCreate()
    If xml.i = 0
        Debug "Failed to create object."
        ProcedureReturn
    EndIf

    CkXml::setCkTag(xml, "set")
    CkXml::ckUpdateChildContent(xml,"sequence|sequence|oid","1.3.6.1.4.1.311.20.2")
    CkXml::ckUpdateAttrAt(xml,"sequence|sequence|asnOctets|universal",1,"tag","30")
    CkXml::ckUpdateAttrAt(xml,"sequence|sequence|asnOctets|universal",1,"constructed","0")
    CkXml::ckUpdateChildContent(xml,"sequence|sequence|asnOctets|universal",s_base64_utf16be)
    CkXml::ckUpdateChildContent(xml,"sequence|sequence[1]|oid","2.5.29.15")
    CkXml::ckUpdateChildContent(xml,"sequence|sequence[1]|bool","1")
    CkXml::ckUpdateAttrAt(xml,"sequence|sequence[1]|asnOctets|bits",1,"n","3")
    ; A0 is hex for decimal 160.
    CkXml::ckUpdateChildContent(xml,"sequence|sequence[1]|asnOctets|bits","A0")
    CkXml::ckUpdateChildContent(xml,"sequence|sequence[2]|oid","2.5.29.37")
    CkXml::ckUpdateChildContent(xml,"sequence|sequence[2]|asnOctets|sequence|oid","1.3.6.1.5.5.7.3.3")

    ; This is the subjectKeyIdentifier extension.
    ; The string "MCzBMQAViXBz8IDt8LsgmJxJ4Xg=" is base64 that decodes to 20 bytes, which is a SHA1 hash.
    ; This is simply a hash of the DER of the public key.

    pubKey.i = CkPublicKey::ckCreate()
    If pubKey.i = 0
        Debug "Failed to create object."
        ProcedureReturn
    EndIf

    CkPrivateKey::ckToPublicKey(privKey,pubKey)
    bdPubKeyDer.i = CkBinData::ckCreate()
    If bdPubKeyDer.i = 0
        Debug "Failed to create object."
        ProcedureReturn
    EndIf

    CkBinData::ckAppendEncoded(bdPubKeyDer,CkPublicKey::ckGetEncoded(pubKey,1,"base64"),"base64")
    ski.s = CkBinData::ckGetHash(bdPubKeyDer,"sha1","base64")

    CkXml::ckUpdateChildContent(xml,"sequence|sequence[3]|oid","2.5.29.14")
    CkXml::ckUpdateChildContent(xml,"sequence|sequence[3]|asnOctets|octets",ski)

    ; Add the extension request to the CSR
    CkCsr::ckSetExtensionRequest(csr,xml)

    ; Generate the CSR with the extension request
    csrPem.s = CkCsr::ckGenCsrPem(csr,privKey)
    If CkCsr::ckLastMethodSuccess(csr) = 0
        Debug CkCsr::ckLastErrorText(csr)
        CkEcc::ckDispose(ecc)
        CkPrng::ckDispose(prng)
        CkPrivateKey::ckDispose(privKey)
        CkCsr::ckDispose(csr)
        CkBinData::ckDispose(bdTemp)
        CkXml::ckDispose(xml)
        CkPublicKey::ckDispose(pubKey)
        CkBinData::ckDispose(bdPubKeyDer)
        ProcedureReturn
    EndIf

    Debug csrPem


    CkEcc::ckDispose(ecc)
    CkPrng::ckDispose(prng)
    CkPrivateKey::ckDispose(privKey)
    CkCsr::ckDispose(csr)
    CkBinData::ckDispose(bdTemp)
    CkXml::ckDispose(xml)
    CkPublicKey::ckDispose(pubKey)
    CkBinData::ckDispose(bdPubKeyDer)


    ProcedureReturn
EndProcedure