/** * @fileoverview Intel(r) AMT Certificate functions * @author Ylian Saint-Hilaire * @version v0.2.0b */ // Check which key pair matches the public key in the certificate function amtcert_linkCertPrivateKey(certs, keys) { for (var i in certs) { var cert = certs[i]; try { if (xxCertPrivateKeys.length == 0) return; var publicKeyPEM = forge.pki.publicKeyToPem(forge.pki.certificateFromAsn1(forge.asn1.fromDer(cert.X509Certificate)).publicKey).substring(28 + 32).replace(/(\r\n|\n|\r)/gm, ""); for (var j = 0; j < keys.length; j++) { if (publicKeyPEM === (keys[j]['DERKey'] + '-----END PUBLIC KEY-----')) { keys[j].XCert = cert; // Link the key pair to the certificate cert.XPrivateKey = keys[j]; // Link the certificate to the key pair } } } catch (e) { console.log(e); } } } // Load a P12 file, decodes it using the password and returns the private key handle function amtcert_loadP12File(file, password, func) { try { // Encode in Base64 so Forge API can parse it. var p12Der = window.forge.util.decode64(btoa(file)); var p12Asn1 = window.forge.asn1.fromDer(p12Der); var p12 = window.forge.pkcs12.pkcs12FromAsn1(p12Asn1, password); // Private key is stored in a shrouded key bag var bags = p12.getBags({ bagType: window.forge.pki.oids.pkcs8ShroudedKeyBag }); console.assert(bags[window.forge.pki.oids.pkcs8ShroudedKeyBag] && bags[window.forge.pki.oids.pkcs8ShroudedKeyBag].length > 0); // Import the Forge private key structure into Web Crypto var privateKey = bags[window.forge.pki.oids.pkcs8ShroudedKeyBag][0].key; var rsaPrivateKey = window.forge.pki.privateKeyToAsn1(privateKey); var privateKeyInfo = window.forge.pki.wrapRsaPrivateKey(rsaPrivateKey); var pkcs8 = window.forge.asn1.toDer(privateKeyInfo).getBytes(); // Get the issuer attributes var certBags = p12.getBags({ bagType: window.forge.pki.oids.certBag }); var issuerAttributes = certBags[window.forge.pki.oids.certBag][0].cert.subject.attributes; var bags1 = p12.getBags({ bagType: forge.pki.oids.certBag }); var cert = bags1[forge.pki.oids.certBag][0].cert; func(privateKey, issuerAttributes, cert); return true; } catch (ex) { } return false; } function amtcert_signWithCaKey(DERKey, caPrivateKey, certAttributes, issuerAttributes, extKeyUsage) { if (!caPrivateKey || caPrivateKey == null) { var certAndKey = amtcert_createCertificate(issuerAttributes); caPrivateKey = certAndKey.key; } return amtcert_createCertificate(certAttributes, caPrivateKey, DERKey, issuerAttributes, extKeyUsage); } // --- Extended Key Usage OID's --- // 1.3.6.1.5.5.7.3.1 = TLS Server certificate // 1.3.6.1.5.5.7.3.2 = TLS Client certificate // 2.16.840.1.113741.1.2.1 = Intel AMT Remote Console // 2.16.840.1.113741.1.2.2 = Intel AMT Local Console // 2.16.840.1.113741.1.2.3 = Intel AMT Client Setup Certificate (Zero-Touch) // Generate a certificate with a set of attributes signed by a rootCert. If the rootCert is obmitted, the generated certificate is self-signed. function amtcert_createCertificate(certAttributes, caPrivateKey, DERKey, issuerAttributes, extKeyUsage) { // Generate a keypair and create an X.509v3 certificate var keys, cert = forge.pki.createCertificate(); if (!DERKey) { keys = forge.pki.rsa.generateKeyPair(2048); cert.publicKey = keys.publicKey; } else { cert.publicKey = forge.pki.publicKeyFromPem('-----BEGIN PUBLIC KEY-----' + DERKey + '-----END PUBLIC KEY-----'); } cert.serialNumber = '' + Math.floor((Math.random() * 100000) + 1); cert.validity.notBefore = new Date(2018, 0, 1); //cert.validity.notBefore.setFullYear(cert.validity.notBefore.getFullYear() - 1); // Create a certificate that is valid one year before, to make sure out-of-sync clocks don't reject this cert. cert.validity.notAfter = new Date(2049, 11, 31); //cert.validity.notAfter.setFullYear(cert.validity.notAfter.getFullYear() + 20); var attrs = []; if (certAttributes['CN']) attrs.push({ name: 'commonName', value: certAttributes['CN'] }); if (certAttributes['C']) attrs.push({ name: 'countryName', value: certAttributes['C'] }); if (certAttributes['ST']) attrs.push({ shortName: 'ST', value: certAttributes['ST'] }); if (certAttributes['O']) attrs.push({ name: 'organizationName', value: certAttributes['O'] }); cert.setSubject(attrs); if (caPrivateKey) { // Use root attributes var rootattrs = []; if (issuerAttributes['CN']) rootattrs.push({ name: 'commonName', value: issuerAttributes['CN'] }); if (issuerAttributes['C']) rootattrs.push({ name: 'countryName', value: issuerAttributes['C'] }); if (issuerAttributes['ST']) rootattrs.push({ shortName: 'ST', value: issuerAttributes['ST'] }); if (issuerAttributes['O']) rootattrs.push({ name: 'organizationName', value: issuerAttributes['O'] }); cert.setIssuer(rootattrs); } else { // Use our own attributes cert.setIssuer(attrs); } if (caPrivateKey == undefined) { // Create a root certificate cert.setExtensions([{ name: 'basicConstraints', cA: true }, { name: 'nsCertType', sslCA: true, emailCA: true, objCA: true }, { name: 'subjectKeyIdentifier' }]); } else { if (extKeyUsage == null) { extKeyUsage = { name: 'extKeyUsage', serverAuth: true, } } else { extKeyUsage.name = 'extKeyUsage'; } /* { name: 'extKeyUsage', serverAuth: true, clientAuth: true, codeSigning: true, emailProtection: true, timeStamping: true, '2.16.840.1.113741.1.2.1': true } */ // Create a leaf certificate cert.setExtensions([{ name: 'basicConstraints' }, { name: 'keyUsage', keyCertSign: true, digitalSignature: true, nonRepudiation: true, keyEncipherment: true, dataEncipherment: true }, extKeyUsage, { name: 'nsCertType', client: true, server: true, email: true, objsign: true, }, { name: 'subjectKeyIdentifier' }]); } // Self-sign certificate if (caPrivateKey) { cert.sign(caPrivateKey, forge.md.sha256.create()); } else { cert.sign(keys.privateKey, forge.md.sha256.create()); } if (DERKey) { return cert; } else { return { 'cert': cert, 'key': keys.privateKey }; } } function _stringToArrayBuffer(str) { var buf = new ArrayBuffer(str.length); var bufView = new Uint8Array(buf); for (var i = 0, strLen = str.length; i < strLen; i++) { bufView[i] = str.charCodeAt(i); } return buf; } function _arrayBufferToString(buffer) { var binary = ''; var bytes = new Uint8Array(buffer); var len = bytes.byteLength; for (var i = 0; i < len; i++) { binary += String.fromCharCode(bytes[i]); } return binary; }