You’ve already set up Certificate-Based Authentication (CBA) in your tenant — your Root CA is uploaded, the authentication method is enabled, and username bindings are configured. Now you need to issue certificates for additional users. This guide covers generating, packaging, and deploying user certificates on both macOS and Windows, plus automating deployment for Windows Entra enrollment.


Prerequisites

  • CBA is enabled in your Entra ID tenant (see the companion article: Setting Up CBA for a New Tenant)
  • Your Root CA files (rootCA.key and rootCA.crt) are accessible
  • OpenSSL is installed on your machine
  • The new user’s account already exists in Entra ID and you know their UPN (e.g., jane@yourdomain.com)

Step 1: Generate the User’s Private Key and CSR

Every user gets their own key pair and certificate. The critical requirement is including the user’s UPN in the Subject Alternative Name using the Microsoft UPN OID.

On macOS / Linux

bash

openssl genrsa -out jane-cba.key 2048

openssl req -new -key jane-cba.key \
  -out jane-cba.csr \
  -subj "/CN=jane@yourdomain.com" \
  -addext "subjectAltName=otherName:1.3.6.1.4.1.311.20.2.3;UTF8:jane@yourdomain.com"

On Windows (PowerShell or Git Bash)

bash

openssl genrsa -out jane-cba.key 2048

openssl req -new -key jane-cba.key -out jane-cba.csr -subj "/CN=jane@yourdomain.com" -addext "subjectAltName=otherName:1.3.6.1.4.1.311.20.2.3;UTF8:jane@yourdomain.com"

Replace jane@yourdomain.com with the user’s actual UPN in Entra ID. The UPN must match exactly — including case — for the username binding to work.


Step 2: Sign the Certificate with Your Root CA

bash

openssl x509 -req -in jane-cba.csr \
  -CA rootCA.crt -CAkey rootCA.key -CAcreateserial \
  -out jane-cba.crt -days 365 -sha256 \
  -copy_extensions copyall

The -copy_extensions copyall flag is essential — it copies the SAN from the CSR into the signed certificate. Without it, the SAN is silently dropped and CBA authentication will fail.


Step 3: Bundle into a .pfx File

On macOS

If you’re running OpenSSL 3.x (most modern Macs), use the -legacy flag so macOS Keychain can read the file:

bash

openssl pkcs12 -export -out jane-cba.pfx \
  -inkey jane-cba.key \
  -in jane-cba.crt \
  -certfile rootCA.crt \
  -legacy

On Windows

bash

openssl pkcs12 -export -out jane-cba.pfx -inkey jane-cba.key -in jane-cba.crt -certfile rootCA.crt

You’ll be prompted for an export password. For manual installs, pick something secure. For automated deployments, you’ll embed this password in your deployment script, so be aware of that tradeoff.

Tip: When prompted interactively, avoid special characters like @, !, # in the password — shells can interpret them unexpectedly. Stick to alphanumeric passwords to avoid “MAC verification failed” headaches.


Step 4: Import the Certificate on the User’s Machine

On macOS

Import both the user certificate and the root CA:

bash

security import jane-cba.pfx -k ~/Library/Keychains/login.keychain-db -P "YourPassword"
security import rootCA.cer -k ~/Library/Keychains/login.keychain-db

If the root CA was already imported on this machine (e.g., for another user), the second command will note it’s a duplicate, which is harmless.

Troubleshooting: “MAC verification failed during PKCS12 import”

This means the .pfx was created with OpenSSL 3.x’s newer encryption format. Recreate it with the -legacy flag (see Step 3).

On Windows — Manual Install

GUI method:

  1. Double-click the .pfx file
  2. Select Current User as the store location
  3. Enter the export password
  4. Accept the defaults and complete the wizard

Command line (run as Administrator):

powershell

certutil -addstore Root rootCA.cer
certutil -importpfx jane-cba.pfx

You’ll be prompted for the .pfx password.

On Windows — Automated via autounattend.xml

If you’re deploying Windows via USB with an unattended install, you can import the certificate automatically during setup.

USB folder structure:

ESD-USB:\
├── autounattend.xml
└── Certs\
    ├── rootCA.cer
    └── jane-cba.pfx

Add this to your autounattend.xml inside the appropriate settings pass (e.g., oobeSystem or specialize):

xml

<RunSynchronousCommand wcm:action="add">
    <Order>1</Order>
    <Path>powershell -ExecutionPolicy Bypass -Command "$d=(Get-Volume -FileSystemLabel 'ESD-USB').DriveLetter; certutil -addstore Root ${d}:\Certs\rootCA.cer; certutil -importpfx -p 'YourPassword' ${d}:\Certs\jane-cba.pfx"</Path>
    <Description>Import CBA Certificates</Description>
</RunSynchronousCommand>

This command dynamically finds the USB drive by its volume label (ESD-USB), so it works regardless of which drive letter Windows assigns.

Security note: The .pfx password is stored in plaintext in the XML. Treat the USB as a sensitive asset, and consider wiping or rotating the certificate after deployment.


Step 5: Test the Login

  1. Fully quit the browser (Cmd+Q on macOS, or close all windows on Windows)
  2. Open the browser and go to https://login.microsoftonline.com
  3. Enter the user’s email address
  4. Choose “Use a certificate or smart card”
  5. Select the certificate from the picker dialog
  6. On macOS, enter the Mac login password when the Keychain prompt appears — click Always Allow to avoid being asked again

Step 6: Set CBA as the Default Sign-In Method

After a successful first login with the certificate, the user can set CBA as their default authentication method:

  1. Go to https://mysignins.microsoft.com/security-info
  2. Click “Change default sign-in method”
  3. Select Certificate-based authentication
  4. Save

Note: You cannot change another user’s default sign-in method from the Entra admin center. Each user must set their own default from the My Security Info portal.


Scripting Bulk User Certificate Generation

If you need to issue certificates for many users at once, here’s a bash script that automates the process:

bash

#!/bin/bash

# List of user UPNs
USERS=(
  "jane@yourdomain.com"
  "john@yourdomain.com"
  "alex@yourdomain.com"
)

PFX_PASSWORD="TempDeploy2024"

for UPN in "${USERS[@]}"; do
  USERNAME=$(echo "$UPN" | cut -d'@' -f1)
  echo "Generating certificate for $UPN..."

  # Generate key
  openssl genrsa -out "${USERNAME}-cba.key" 2048 2>/dev/null

  # Generate CSR with SAN
  openssl req -new \
    -key "${USERNAME}-cba.key" \
    -out "${USERNAME}-cba.csr" \
    -subj "/CN=${UPN}" \
    -addext "subjectAltName=otherName:1.3.6.1.4.1.311.20.2.3;UTF8:${UPN}" \
    2>/dev/null

  # Sign with Root CA
  openssl x509 -req \
    -in "${USERNAME}-cba.csr" \
    -CA rootCA.crt -CAkey rootCA.key -CAcreateserial \
    -out "${USERNAME}-cba.crt" -days 365 -sha256 \
    -copy_extensions copyall \
    2>/dev/null

  # Bundle PFX (with -legacy for macOS compatibility)
  openssl pkcs12 -export \
    -out "${USERNAME}-cba.pfx" \
    -inkey "${USERNAME}-cba.key" \
    -in "${USERNAME}-cba.crt" \
    -certfile rootCA.crt \
    -legacy \
    -password "pass:${PFX_PASSWORD}" \
    2>/dev/null

  echo "  Created ${USERNAME}-cba.pfx"

  # Clean up intermediate files
  rm -f "${USERNAME}-cba.key" "${USERNAME}-cba.csr" "${USERNAME}-cba.crt"
done

echo "Done. All .pfx files ready for deployment."

Windows equivalent (PowerShell)

powershell

$users = @(
    "jane@yourdomain.com",
    "john@yourdomain.com",
    "alex@yourdomain.com"
)

$pfxPassword = "TempDeploy2024"

foreach ($upn in $users) {
    $username = $upn.Split("@")[0]
    Write-Host "Generating certificate for $upn..."

    openssl genrsa -out "$username-cba.key" 2048 2>$null

    openssl req -new `
        -key "$username-cba.key" `
        -out "$username-cba.csr" `
        -subj "/CN=$upn" `
        -addext "subjectAltName=otherName:1.3.6.1.4.1.311.20.2.3;UTF8:$upn"

    openssl x509 -req `
        -in "$username-cba.csr" `
        -CA rootCA.crt -CAkey rootCA.key -CAcreateserial `
        -out "$username-cba.crt" -days 365 -sha256 `
        -copy_extensions copyall

    openssl pkcs12 -export `
        -out "$username-cba.pfx" `
        -inkey "$username-cba.key" `
        -in "$username-cba.crt" `
        -certfile rootCA.crt `
        -password "pass:$pfxPassword"

    Write-Host "  Created $username-cba.pfx"

    Remove-Item "$username-cba.key", "$username-cba.csr", "$username-cba.crt" -ErrorAction SilentlyContinue
}

Write-Host "Done. All .pfx files ready for deployment."

Deploying Certificates via Intune (SCEP/PKCS)

For larger organizations, manually distributing .pfx files doesn’t scale. Microsoft Intune supports automated certificate deployment through SCEP and PKCS certificate profiles. The high-level process is:

  1. Set up a certificate connector — Install the Microsoft Intune Certificate Connector on a Windows Server that has access to your CA
  2. Create a Trusted Certificate profile — Deploy your root CA certificate to devices
  3. Create a PKCS or SCEP certificate profile — Configure Intune to automatically issue and deploy user certificates to enrolled devices

This is a more complex setup but eliminates the need to manually handle .pfx files for each user. Refer to Microsoft’s documentation on Intune certificate connectors for detailed steps.


Revoking a User’s Certificate

If a user leaves the organization or their certificate is compromised, you have several options:

  • Disable the user account in Entra ID — this prevents sign-in regardless of the certificate
  • Delete the certificate from the user’s machine
  • Set up CRL validation in the CBA configuration and publish a Certificate Revocation List through your CA

For immediate revocation without CRL infrastructure, disabling the user account is the fastest approach.


Quick Reference: Commands at a Glance

TaskCommand
Generate keyopenssl genrsa -out user.key 2048
Create CSR with SANopenssl req -new -key user.key -out user.csr -subj "/CN=user@domain.com" -addext "subjectAltName=otherName:1.3.6.1.4.1.311.20.2.3;UTF8:user@domain.com"
Sign certificateopenssl x509 -req -in user.csr -CA rootCA.crt -CAkey rootCA.key -CAcreateserial -out user.crt -days 365 -sha256 -copy_extensions copyall
Create PFX (macOS)openssl pkcs12 -export -out user.pfx -inkey user.key -in user.crt -certfile rootCA.crt -legacy
Create PFX (Windows)openssl pkcs12 -export -out user.pfx -inkey user.key -in user.crt -certfile rootCA.crt
Import on macOSsecurity import user.pfx -k ~/Library/Keychains/login.keychain-db -P "password"
Import on Windowscertutil -importpfx user.pfx