Search code examples
windowspowershellsslfirefoxcertificate

Get MOZILLA_PKIX_ERROR_CA_CERT_USED_AS_END_ENTITY with Self-Signed Certificate on FireFox


I got the subject error when trying to use a certificate I created using the following command line:

 openssl.exe req -x509 -nodes -sha256 -days 3650 -subj "/CN=mysite.local" -newkey rsa:2048 -keyout mysite.local.key -out mysite.local.crt

I found another issue on this site that referenced the same error:

Looks like that certificate has a basicConstraints extension with the value cA: TRUE. We stopped allowing CA certificates to act as end-entity certificates. That certificate should be regenerated without the basicConstraints extension. This is also explained at https://wiki.mozilla.org/SecurityEngineering/x509Certs

I followed the referenced link and tried follow the instructions under Self Signed Certs. Step 1 worked. Step 2 gave error: Ignoring -days; not generating a certificate.

I'm on Windows 10 Pro, using OpenSSL 1.1.1f 31 Mar 2020. I have not found any reference to that error anywhere on the web. Any ideas?


Solution

  • Regarding this comment from the OP: " I'm trying to set up HTTPS for communication between a front end and back end API server that are on different computers on a network. That is why I was trying to generate a self signed certificate. Is there a more standard approach to this problem?"

    You can use the script below to create a cert, import it to the trusted root store on the API server, and configure traffic over a given port to use the cert for encryption(SSL I think...). Then, from the cert management GUI (Manage Computer Certificates), you can export the cert you just created and import it into your front-end server.

    Edited to reflect OP's comment on pipeline output issues.

    param(
        [string] $certPass,
        [string] $portForTraffic,
        [string] $dnsName = '<HOST>.<DOMAIN>.<DOMAIN_SUFFIX>', # <== ex: server.contoso.com 
        [int] $certValidForDays = 365
    )
    
    Set-StrictMode -Version Latest
    $ErrorActionPreference = "Stop";
    #Requires -Version 5.0
    
    [string] $certStoreLocation = 'Cert:\LocalMachine'
    
    function CreateSelfSignedCert(
        [Parameter(Mandatory=$true)]
        [string] $dnsName,
    
        [Parameter(Mandatory=$false)]
        [string] $storeLocation = $certStoreLocation,
    
        [Parameter(Mandatory=$false)]
        [int] $certValidDays = $certValidForDays
    ){    
        $certificate = New-SelfSignedCertificate `
            -DnsName $dnsName `
            -CertStoreLocation "$storeLocation\My" `
            -NotAfter $((Get-Date).AddDays($certValidDays)) `
            -Verbose
    
        $certThumbPrint = $certificate.Thumbprint
    
        $returnObj = [PSCustomObject] @{
            ThumbPrint = $certThumbPrint;
        }
        return $returnObj;
    }
    
    function ExportCert(
        [Parameter(Mandatory=$true)]
        [string] $certThumbPrint,
    
        [Parameter(Mandatory=$true)]
        [string] $certPass,
    
        [Parameter(Mandatory=$true)]
        [string] $workDir,
    
        [Parameter(Mandatory=$false)]
        [string] $storeLocation = $certStoreLocation
    ){    
        $certificatePath = "$storeLocation\My\$certThumbPrint"
        $secureString = ConvertTo-SecureString -String $certPass -Force -AsPlainText
    
        $tempDir = "$workDir\pfx_temp"
        $pfxFilePath = "$tempDir\temp.pfx"    
        if( (Test-Path -Path $tempDir) -eq $false ){
            New-Item -ItemType Directory -Path $tempDir -Verbose | Out-Null
        }
        # ...so export it...
        $fileInfo = Export-PfxCertificate `
            -FilePath $pfxFilePath `
            -Cert $certificatePath `
            -Password $secureString `
            -Verbose
        Write-Host "$fileInfo"
        
        return $pfxFilePath
    }
    
    function ImportCertToRoot(
        [Parameter(Mandatory=$true)]
        [string] $pfxPath,
    
        [Parameter(Mandatory=$true)]
        [string] $certPass,
    
        [Parameter(Mandatory=$false)]
        [string] $storeLocation = $certStoreLocation
    ) {
        $secureString = ConvertTo-SecureString -String $certPass -Force -AsPlainText
        Write-Host "Attempting to import cert from: $pfxPath"
        Import-PfxCertificate `
            -FilePath $pfxPath `
            -CertStoreLocation "$storeLocation\Root" `
            -Password $secureString `
            -Verbose | Out-Null
        
        Remove-Item -Path $pfxPath -Force -Verbose
    }
    
    function ConfigureSslForPortOnHost(
        [Parameter(Mandatory=$true)]
        [string] $port,
    
        [Parameter(Mandatory=$true)]
        [string] $certThumbPrint
    ) {
        Write-Host -ForegroundColor Yellow "Attempting to add ssl rule using NETSH. Using cert with thumbprint: $($certThumbPrint)"
        
        Invoke-Expression "netsh http delete sslcert ipport=0.0.0.0:$port"
        Invoke-Expression "netsh http add sslcert ipport=0.0.0.0:$port appid='{214124cd-d05b-4309-9af9-9caa44b2b74a}' certhash=$($certThumbPrint)"    
    }
    
    # Create a self-signed cert
    $cert = CreateSelfSignedCert -dnsName $dnsName
    
    # Export the cert so we can later import it to the root store
    $pfxPath = ExportCert -certThumbPrint $cert.ThumbPrint -certPass $certPass -workDir $PSScriptRoot
    
    # Import cert to trusted root
    ImportCertToRoot -pfxPath $pfxPath -certPass $certPass
    
    # Ensure HTTP traffic to specified port on API server is encrypted
    ConfigureSslForPortOnHost -port $portForTraffic -certThumbPrint $cert.ThumbPrint