如何用JavaScript/Angular 2解析X509证书并提取公钥
Got it, let's walk through how to extract the public key from an X509 certificate using JavaScript (this works perfectly for Angular 2+ too, since Angular is just built on top of vanilla JS). Here's a complete, tested solution:
Step 1: Understand the Core Tools
We'll use the Web Crypto API (built into modern browsers) to parse the certificate and extract the public key. First, we need to convert the PEM-formatted certificate string into an ArrayBuffer—the format the Web Crypto API expects.
Step 2: Vanilla JavaScript Implementation
Here's a self-contained function set to handle the extraction:
// Helper to convert PEM certificate to ArrayBuffer function pemToArrayBuffer(pem) { // Strip PEM headers/footers and newlines const pemHeader = "-----BEGIN CERTIFICATE-----"; const pemFooter = "-----END CERTIFICATE-----"; const cleanPem = pem.replace(pemHeader, "").replace(pemFooter, "").replace(/\n/g, ""); // Convert Base64 string to Uint8Array const binaryString = window.atob(cleanPem); const bytes = new Uint8Array(binaryString.length); for (let i = 0; i < binaryString.length; i++) { bytes[i] = binaryString.charCodeAt(i); } return bytes.buffer; } // Main function to extract public key async function extractPublicKeyFromCertificate(pemCertificate) { try { const certBuffer = pemToArrayBuffer(pemCertificate); // Import the X509 certificate into the Web Crypto API const certificate = await window.crypto.subtle.importCertificate( "x509", certBuffer, { name: "RSASSA-PKCS1-v1_5", // Match your cert's algorithm (e.g., "ECDSA" for elliptic curve) hash: "SHA-256" }, false, // We don't need to use the cert for signing/encrypting, just extract the key ["verify"] // Required key usage for public key extraction ); // Extract the public key object from the certificate const publicKey = certificate.publicKey; // Export the public key to SPKI format (PEM-friendly) const spkiBuffer = await window.crypto.subtle.exportKey("spki", publicKey); // Convert ArrayBuffer back to formatted PEM string const base64PublicKey = window.btoa(String.fromCharCode(...new Uint8Array(spkiBuffer))); return `-----BEGIN PUBLIC KEY-----\n${base64PublicKey.match(/.{1,64}/g).join('\n')}\n-----END PUBLIC KEY-----`; } catch (error) { console.error("Error extracting public key:", error); throw error; // Re-throw to let calling code handle errors } } // Usage example with your certificate const certificate = "-----BEGIN CERTIFICATE-----\nMIIFkTCCBHmgAwIBAgIEAOATLTANBgkqhkiG9w0BAQsFADCBkDELMAkGA1UEBhMC\nSU4xKjAoBgNVBAoTIWVNdWRocmEgQ29uc3VtZXIgU2VydmljZXMgTGltaXRlZDEd\nMBsGA1UECxMUQ2VydGlmeWluZyBBdXRob3JpdHkxNjA0BgNVBAMTLWUtTXVkaHJh\nIFN1YiBDQSBmb3..."; extractPublicKeyFromCertificate(certificate) .then(publicKeyPem => { console.log("Extracted Public Key:", publicKeyPem); // Use the public key in your app (e.g., verify signatures, encrypt data) }) .catch(err => { // Handle errors like invalid cert format or unsupported algorithms });
Step 3: Angular 2+ Adaptation
In Angular, you can wrap this logic into a service for reusability across components:
1. Create a Certificate Service
import { Injectable } from '@angular/core'; @Injectable({ providedIn: 'root' }) export class CertificateService { constructor() { } private pemToArrayBuffer(pem: string): ArrayBuffer { const pemHeader = "-----BEGIN CERTIFICATE-----"; const pemFooter = "-----END CERTIFICATE-----"; const cleanPem = pem.replace(pemHeader, "").replace(pemFooter, "").replace(/\n/g, ""); const binaryString = window.atob(cleanPem); const bytes = new Uint8Array(binaryString.length); for (let i = 0; i < binaryString.length; i++) { bytes[i] = binaryString.charCodeAt(i); } return bytes.buffer; } async extractPublicKey(pemCertificate: string): Promise<string> { try { const certBuffer = this.pemToArrayBuffer(pemCertificate); const certificate = await window.crypto.subtle.importCertificate( "x509", certBuffer, { name: "RSASSA-PKCS1-v1_5", hash: "SHA-256" }, false, ["verify"] ); const publicKey = certificate.publicKey; const spkiBuffer = await window.crypto.subtle.exportKey("spki", publicKey); const base64PublicKey = window.btoa(String.fromCharCode(...new Uint8Array(spkiBuffer))); return `-----BEGIN PUBLIC KEY-----\n${base64PublicKey.match(/.{1,64}/g).join('\n')}\n-----END PUBLIC KEY-----`; } catch (error) { console.error("Error extracting public key:", error); throw error; } } }
2. Use the Service in a Component
import { Component, OnInit } from '@angular/core'; import { CertificateService } from './certificate.service'; @Component({ selector: 'app-cert-handler', templateUrl: './cert-handler.component.html' }) export class CertHandlerComponent implements OnInit { certificate = "-----BEGIN CERTIFICATE-----\nMIIFkTCCBHmgAwIBAgIEAOATLTANBgkqhkiG9w0BAQsFADCBkDELMAkGA1UEBhMC\nSU4xKjAoBgNVBAoTIWVNdWRocmEgQ29uc3VtZXIgU2VydmljZXMgTGltaXRlZDEd\nMBsGA1UECxMUQ2VydGlmeWluZyBBdXRob3JpdHkxNjA0BgNVBAMTLWUtTXVkaHJh\nIFN1YiBDQSBmb3..."; publicKey: string | null = null; constructor(private certService: CertificateService) { } ngOnInit(): void { this.getPublicKey(); } async getPublicKey(): Promise<void> { try { this.publicKey = await this.certService.extractPublicKey(this.certificate); console.log("Public Key:", this.publicKey); } catch (err) { console.error("Failed to extract public key:", err); } } }
Key Notes
- Secure Contexts: The Web Crypto API only works over HTTPS or
localhost—your production Angular app must use HTTPS. - Algorithm Matching: If your certificate uses an elliptic curve algorithm (ECDSA), update the
nameparameter inimportCertificateto"ECDSA"and ensure thehashmatches the cert's configured hash (e.g.,"SHA-256"). - PEM Formatting: The
match(/.{1,64}/g)line splits the Base64 string into 64-character lines, which is required for valid PEM public key formatting.
内容的提问来源于stack exchange,提问作者pratik
相关产品推荐
相关产品推荐

