module sideload.certificateidentity; import std.algorithm.searching; import std.digest.sha; import file = std.file; import std.path; import std.uni; import slf4d; import botan.constants; version = X509; import botan.cert.x509.certstor; import botan.cert.x509.x509_crl; import botan.cert.x509.x509self; import botan.pubkey.algo.rsa; import botan.rng.rng; import constants; import server.appleaccount; import server.developersession; import sideload.bundle; class CertificateIdentity { RandomNumberGenerator rng = void; X509Certificate certificate = void; RSAPrivateKey privateKey = void; string keyFile; this(X509Certificate certificate, RSAPrivateKey privateKey) { rng = RandomNumberGenerator.makeRng(); this.certificate = certificate; this.privateKey = privateKey; } this(string configurationPath, DeveloperSession appleAccount) { auto log = getLogger(); scope(success) log.debug_("Certificate retrieved successfully."); string keyPath = configurationPath.buildPath("keys").buildPath(sha1Of(appleAccount.appleId).toHexString().toLower()); if (!file.exists(keyPath)) { file.mkdirRecurse(keyPath); } keyFile = keyPath.buildPath("key.pem"); rng = RandomNumberGenerator.makeRng(); auto teams = appleAccount.listTeams().unwrap(); auto team = teams[0]; if (file.exists(keyFile)) { log.debug_("A key has already been generated"); privateKey = RSAPrivateKey(loadKey(keyFile, rng)); log.debug_("Checking if any certificate online is matching the private key..."); auto certificates = appleAccount.listAllDevelopmentCerts!iOS(team).unwrap(); auto sideloaderCertificates = certificates.find!((cert) => cert.machineName == applicationName); if (sideloaderCertificates.length != 0) { Vector!ubyte certContent; Vector!ubyte ourPublicKey = privateKey.x509SubjectPublicKey(); foreach (cert; sideloaderCertificates) { certContent = Vector!ubyte(cert.certContent); auto x509cert = X509Certificate(certContent, false); if (x509cert.subjectPublicKey().x509SubjectPublicKey() == ourPublicKey) { log.debug_("Matching certificate found."); certificate = X509Certificate(Vector!ubyte(certContent), false); return; } // +/ } } } else { log.debug_("Generating a new RSA key"); privateKey = RSAPrivateKey(rng, 2048); file.write(keyFile, botan.pubkey.pkcs8.PEM_encode(privateKey)); } X509CertOptions subject; subject.country = "US"; subject.state = "STATE"; subject.locality = "LOCAL"; subject.organization = "ORGANIZATION"; subject.common_name = "CN"; auto certRequest = createCertReq(subject, privateKey.m_priv, "SHA-256", rng); log.debug_("Submitting a new certificate request to Apple..."); auto certificateId = appleAccount.submitDevelopmentCSR!iOS(team, certRequest.PEM_encode()).unwrap(); auto appleCertificateInfo = appleAccount.listAllDevelopmentCerts!iOS(team).unwrap().find!((cert) => cert.certificateId == certificateId)[0]; certificate = X509Certificate(Vector!ubyte(appleCertificateInfo.certContent), false); } }