diff --git a/openssl/src/lib.rs b/openssl/src/lib.rs index b283a47993b4f5acfb91e295094dd6730d706a07..4c9b176ae249d7cf1d6f24f36049d93efb840936 100644 --- a/openssl/src/lib.rs +++ b/openssl/src/lib.rs @@ -22,3 +22,4 @@ pub mod bio; pub mod crypto; pub mod ssl; pub mod x509; +pub mod nid; diff --git a/openssl/src/nid.rs b/openssl/src/nid.rs new file mode 100644 index 0000000000000000000000000000000000000000..08424ae85d0b4a2cfe5c9c963fea00f3d81caad8 --- /dev/null +++ b/openssl/src/nid.rs @@ -0,0 +1,170 @@ +#[allow(non_camel_case_types)] +#[derive(Copy, Clone)] +#[repr(usize)] +pub enum Nid { + Undefined, + Rsadsi, + Pkcs, + MD2, + MD4, + MD5, + RC4, + RsaEncryption, + RSA_MD2, + RSA_MD5, + PBE_MD2_DES, + X500, + x509, + CN, + C, + L, + ST, + O, + OU, + RSA, + Pkcs7, + Pkcs7_data, + Pkcs7_signedData, + Pkcs7_envelopedData, + Pkcs7_signedAndEnvelopedData, + Pkcs7_digestData, + Pkcs7_encryptedData, + Pkcs3, + DhKeyAgreement, + DES_ECB, + DES_CFB, + DES_CBC, + DES_EDE, + DES_EDE3, + IDEA_CBC, + IDEA_ECB, + RC2_CBC, + RC2_ECB, + RC2_CFB, + RC2_OFB, + SHA, + RSA_SHA, + DES_EDE_CBC, + DES_EDE3_CBC, + DES_OFB, + IDEA_OFB, + Pkcs9, + Email, + UnstructuredName, + ContentType, + MessageDigest, + SigningTime, + CounterSignature, + UnstructuredAddress, + ExtendedCertificateAttributes, + Netscape, + NetscapeCertExtention, + NetscapeDatatype, + DES_EDE_CFB64, + DES_EDE3_CFB64, + DES_EDE_OFB64, + DES_EDE3_OFB64, + SHA1, + RSA_SHA1, + DSA_SHA, + DSA_OLD, + PBE_SHA1_RC2_64, + PBKDF2, + DSA_SHA1_OLD, + NetscapeCertType, + NetscapeBaseUrl, + NetscapeRevocationUrl, + NetscapeCARevocationUrl, + NetscapeRenewalUrl, + NetscapeCAPolicyUrl, + NetscapeSSLServerName, + NetscapeComment, + NetscapeCertSequence, + DESX_CBC, + ID_CE, + SubjectKeyIdentifier, + KeyUsage, + PrivateKeyUsagePeriod, + SubjectAltName, + IssuerAltName, + BasicConstraints, + CrlNumber, + CertificatePolicies, + AuthorityKeyIdentifier, + BF_CBC, + BF_ECB, + BF_OFB, + MDC2, + RSA_MDC2, + RC4_40, + RC2_40_CBC, + G, + S, + I, + UID, + CrlDistributionPoints, + RSA_NP_MD5, + SN, + T, + D, + CAST5_CBC, + CAST5_ECB, + CAST5_CFB, + CAST5_OFB, + PbeWithMD5AndCast5CBC, + DSA_SHA1, + MD5_SHA1, + RSA_SHA1_2, + DSA, + RIPEMD160, + RSA_RIPEMD160, + RC5_CBC, + RC5_ECB, + RC5_CFB, + RC5_OFB, + RLE, + ZLIB, + ExtendedKeyUsage, + PKIX, + ID_KP, + ServerAuth, + ClientAuth, + CodeSigning, + EmailProtection, + TimeStamping, + MsCodeInd, + MsCodeCom, + MsCtlSigh, + MsSGC, + MsEFS, + NsSGC, + DeltaCRL, + CRLReason, + InvalidityDate, + SXNetID, + Pkcs12, + PBE_SHA1_RC4_128, + PBE_SHA1_RC4_40, + PBE_SHA1_3DES, + PBE_SHA1_2DES, + PBE_SHA1_RC2_128, + PBE_SHA1_RC2_40, + KeyBag, + Pkcs8ShroudedKeyBag, + CertBag, + CrlBag, + SecretBag, + SafeContentsBag, + FriendlyName, + LocalKeyID, + X509Certificate, + SdsiCertificate, + X509Crl, + PBES2, + PBMAC1, + HmacWithSha1, + ID_QT_CPS, + ID_QT_UNOTICE, + RC2_64_CBC, + SMIMECaps +} diff --git a/openssl/src/ssl/tests.rs b/openssl/src/ssl/tests.rs index 6759b2bb7e42dd3c5622285abf3d1a0008f7b8e5..ec4f2b0192c84c59d29e4132658d08610478c2d7 100644 --- a/openssl/src/ssl/tests.rs +++ b/openssl/src/ssl/tests.rs @@ -223,7 +223,7 @@ run_test!(verify_callback_data, |method, stream| { // in DER format. // Command: openssl x509 -in test/cert.pem -outform DER | openssl dgst -sha256 // Please update if "test/cert.pem" will ever change - let node_hash_str = "46e3f1a6d17a41ce70d0c66ef51cee2ab4ba67cac8940e23f10c1f944b49fb5c"; + let node_hash_str = "db400bb62f1b1f29c3b8f323b8f7d9dea724fdcd67104ef549c772ae3749655b"; let node_id = node_hash_str.from_hex().unwrap(); ctx.set_verify_with_data(SSL_VERIFY_PEER, callback, node_id); ctx.set_verify_depth(1); @@ -320,7 +320,7 @@ run_test!(get_peer_certificate, |method, stream| { let stream = SslStream::new(&SslContext::new(method).unwrap(), stream).unwrap(); let cert = stream.get_peer_certificate().unwrap(); let fingerprint = cert.fingerprint(SHA256).unwrap(); - let node_hash_str = "46e3f1a6d17a41ce70d0c66ef51cee2ab4ba67cac8940e23f10c1f944b49 fb5c"; + let node_hash_str = "db400bb62f1b1f29c3b8f323b8f7d9dea724fdcd67104ef549c772ae3749655b"; let node_id = node_hash_str.from_hex().unwrap(); assert_eq!(node_id, fingerprint) }); diff --git a/openssl/src/x509/mod.rs b/openssl/src/x509/mod.rs index c0e730f771e4a540a1e8ca2a2b54515443ee46ac..0f7585cc99115e749ff0949140ece592920287f3 100644 --- a/openssl/src/x509/mod.rs +++ b/openssl/src/x509/mod.rs @@ -1,11 +1,14 @@ -use libc::{c_char, c_int, c_long, c_ulong, c_uint}; +use libc::{c_char, c_int, c_long, c_ulong, c_uint, c_void}; use std::io; use std::io::prelude::*; use std::cmp::Ordering; -use std::ffi::CString; +use std::ffi::{CString, CStr}; use std::iter::repeat; use std::mem; use std::ptr; +use std::ops::Deref; +use std::fmt; +use std::str; use asn1::{Asn1Time}; use bio::{MemBio}; @@ -15,11 +18,50 @@ use crypto::pkey::{PKey,Parts}; use crypto::rand::rand_bytes; use ffi; use ssl::error::{SslError, StreamError}; +use nid; #[cfg(test)] mod tests; +pub struct SslString<'s> { + s : &'s str +} + +impl<'s> Drop for SslString<'s> { + fn drop(&mut self) { + unsafe { ffi::CRYPTO_free(self.s.as_ptr() as *mut c_void); } + } +} + +impl<'s> Deref for SslString<'s> { + type Target = str; + + fn deref(&self) -> &str { + self.s + } +} + +impl<'s> SslString<'s> { + pub unsafe fn new(buf: *const c_char) -> SslString<'s> { + SslString { + s: str::from_utf8(CStr::from_ptr(buf).to_bytes()).unwrap() + } + } +} + +impl<'s> fmt::Display for SslString<'s> { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "{:?}", self) + } +} + +impl<'s> fmt::Debug for SslString<'s> { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "{:?}", self) + } +} + #[derive(Copy, Clone)] #[repr(i32)] pub enum X509FileType { @@ -458,6 +500,44 @@ pub struct X509Name<'x> { name: *mut ffi::X509_NAME } +#[allow(dead_code)] +pub struct X509NameEntry<'x> { + x509_name: &'x X509Name<'x>, + ne: *mut ffi::X509_NAME_ENTRY +} + +impl <'x> X509Name<'x> { + pub fn text_by_nid(&self, nid: nid::Nid) -> Option { + unsafe { + let loc = ffi::X509_NAME_get_index_by_NID(self.name, nid as c_int, -1); + if loc == -1 { + return None; + } + + let ne = ffi::X509_NAME_get_entry(self.name, loc); + if ne.is_null() { + return None; + } + + let asn1_str = ffi::X509_NAME_ENTRY_get_data(ne); + if asn1_str.is_null() { + return None; + } + + let mut str_from_asn1 : *mut c_char = ptr::null_mut(); + let len = ffi::ASN1_STRING_to_UTF8(&mut str_from_asn1, asn1_str); + + if len < 0 { + return None + } + + assert!(!str_from_asn1.is_null()); + + Some(SslString::new(str_from_asn1)) + } + } +} + macro_rules! make_validation_error( ($ok_val:ident, $($name:ident = $val:ident,)+) => ( #[derive(Copy, Clone)] diff --git a/openssl/src/x509/tests.rs b/openssl/src/x509/tests.rs index e9a8a4a5e508cd8ff58f4a4d29c61076e7a57542..6d95b9666c06dccc15351f94bdbfaaa3d7b29a0b 100644 --- a/openssl/src/x509/tests.rs +++ b/openssl/src/x509/tests.rs @@ -7,6 +7,7 @@ use crypto::hash::Type::{SHA256}; use x509::{X509, X509Generator}; use x509::KeyUsage::{DigitalSignature, KeyEncipherment}; use x509::ExtKeyUsage::{ClientAuth, ServerAuth}; +use nid::Nid; #[test] fn test_cert_gen() { @@ -46,8 +47,25 @@ fn test_cert_loading() { // in DER format. // Command: openssl x509 -in test/cert.pem -outform DER | openssl dgst -sha256 // Please update if "test/cert.pem" will ever change - let hash_str = "46e3f1a6d17a41ce70d0c66ef51cee2ab4ba67cac8940e23f10c1f944b49fb5c"; + let hash_str = "db400bb62f1b1f29c3b8f323b8f7d9dea724fdcd67104ef549c772ae3749655b"; let hash_vec = hash_str.from_hex().unwrap(); assert_eq!(fingerprint, hash_vec); } + +#[test] +fn test_subject_read_cn() { + let cert_path = Path::new("test/cert.pem"); + let mut file = File::open(&cert_path) + .ok() + .expect("Failed to open `test/cert.pem`"); + + let cert = X509::from_pem(&mut file).ok().expect("Failed to load PEM"); + let subject = cert.subject_name(); + let cn = match subject.text_by_nid(Nid::CN) { + Some(x) => x, + None => panic!("Failed to read CN from cert") + }; + + assert_eq!(&cn as &str, "test_cert") +} diff --git a/openssl/test/cert.pem b/openssl/test/cert.pem index 1523c736b3a9bc4fa43b7ddd1f933cbd4fd56d99..0ca22e3deea38b2fab598a9c70d4abc63ca7a805 100644 --- a/openssl/test/cert.pem +++ b/openssl/test/cert.pem @@ -1,21 +1,24 @@ -----BEGIN CERTIFICATE----- -MIIDXTCCAkWgAwIBAgIJAMWJMG/NYWQyMA0GCSqGSIb3DQEBCwUAMEUxCzAJBgNV -BAYTAkFVMRMwEQYDVQQIDApTb21lLVN0YXRlMSEwHwYDVQQKDBhJbnRlcm5ldCBX -aWRnaXRzIFB0eSBMdGQwHhcNMTQxMTIwMDU0MjIxWhcNMTcxMTE5MDU0MjIxWjBF -MQswCQYDVQQGEwJBVTETMBEGA1UECAwKU29tZS1TdGF0ZTEhMB8GA1UECgwYSW50 -ZXJuZXQgV2lkZ2l0cyBQdHkgTHRkMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIB -CgKCAQEA2E9uYoLpX4eMGz6+l+1ZdD11Y1PQjNjqSA7/nq0Q6gogPLds99a+Ca7B -2w6mWGMpCQbJTf0tOkdF6Td/gwIBNYtHuCIAiPh2Gbm6oZErVIXWwWuTWC2r7myB -0ePga5ZAE9SqsFqMEuhWikEK1+ae1CCfmbogsQSXyl4+EVN7xAwdi6yUtRL/92nn -ImKdwDBhuqzdBpBODQW/VCn0KG54CvWdwT0iqg7CvLuXQGyxM8K17SAiBtn6N38S -0jeL4D9IrBfi9PCYGpAn3jKr4oBEJVRCNvvni3Q9ikJ+GEF5nvLLVM+I98/o0vCu -Y2o7+1LiwViGONJ1BfRgdFWMjz0BfQIDAQABo1AwTjAdBgNVHQ4EFgQU509vewJT -k6qdvjT8e52gTE4+V9EwHwYDVR0jBBgwFoAU509vewJTk6qdvjT8e52gTE4+V9Ew -DAYDVR0TBAUwAwEB/zANBgkqhkiG9w0BAQsFAAOCAQEAnLxMvrhgQrdKUbd+RSl3 -i6tEfexDepO5QOMIL/m7w/OAkXddu7Y/IuLSgAztp7cu8tQeeBTqbO9T9XKRd1ZD -hMN3QPZwX1ftREPd1mhe3LQgJ/Q3AbrtlW+0XcANBCTiYi19X193sU2a3Z2nzd5v -vSvrP1W3Yxzvu7Jwvhgl20BQ0fREpPVfZTrJRhg8/jdLA8TmKZA7012LKh59BCEX -dXgXc3KYb+Fn8usj79P1nP1YhYmX0Lp0IuC0i1z+FoP/NxNMe+ebXPjM9KlkvQK1 -Vy9sIxV9MAlXpGsMvBJAte94JRikYkQTPjMT1DGQQYGpHIYb3a8jcWvmZPEEaqhB -Ag== +MIID9DCCAtygAwIBAgIJALuA8gDKi5EzMA0GCSqGSIb3DQEBCwUAMFkxCzAJBgNV +BAYTAkFVMRMwEQYDVQQIEwpTb21lLVN0YXRlMSEwHwYDVQQKExhJbnRlcm5ldCBX +aWRnaXRzIFB0eSBMdGQxEjAQBgNVBAMUCXRlc3RfY2VydDAeFw0xNTA1MTExNzI0 +MThaFw0xNjA1MTAxNzI0MThaMFkxCzAJBgNVBAYTAkFVMRMwEQYDVQQIEwpTb21l +LVN0YXRlMSEwHwYDVQQKExhJbnRlcm5ldCBXaWRnaXRzIFB0eSBMdGQxEjAQBgNV +BAMUCXRlc3RfY2VydDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBANYg +8apqh+nHYBL/KS9SLtDmhTR2s+H3mk7avXACahMEt/Eapsft5YOJ8JAkPbkoyd91 +QtxbrDF1M3rtTfWwHrf4jCeZ6kt2CSvYyJCPP/7JbWPdMDsYFBtoBOEVMdjOLr4R +8tAar2t1Gu63Mu7LWeYvyFKqJpDkP30/k+OED79l7rOQg6eVN+Qjr1wx3VSBhovs +UShGnSRw5YWiKnvvUnHwq2eXkwXFOdkhRNsTpWgV+EZsOdunczGbEG4qa+iwJjod +/b8O9R1rIr12mwgT2U3GHNpJU0I+Qu2063nONndhMfES3md6QCIlKMVYDSU/Wli5 +sLxTxykXWv548Ib8Yv8CAwEAAaOBvjCBuzAdBgNVHQ4EFgQUGec/TF+Ok3BoEAqX +yvEi9+Emy9QwgYsGA1UdIwSBgzCBgIAUGec/TF+Ok3BoEAqXyvEi9+Emy9ShXaRb +MFkxCzAJBgNVBAYTAkFVMRMwEQYDVQQIEwpTb21lLVN0YXRlMSEwHwYDVQQKExhJ +bnRlcm5ldCBXaWRnaXRzIFB0eSBMdGQxEjAQBgNVBAMUCXRlc3RfY2VydIIJALuA +8gDKi5EzMAwGA1UdEwQFMAMBAf8wDQYJKoZIhvcNAQELBQADggEBALwDb82BBTfz +X+7rENv+f76X+DkHjt6QzCr9f1PYpbIle5/XaxCp+Rkz1BGZTmPRPURpAzweznlG +kY5KydZ1+XdxPHh2zReBS00KxMElmlMKWp7nOnIKohzcQxTFp4VZ7smb9ymXYdYQ +nRqaLIM1AKsj+0ulqsSbKggIuUZBvfrAdC3J6//3CXSdvQLJGzYPtTLUddQLN9pv +GXrdNmvK3BjP+kokAjTt+DMMbIIZZitUVjKXqB7WS/Mqss1P2mdagJmOaD2mL3pY +HDCCpquJ1SKN3g33hOA0pMRxGskyJI8x71mnej0StbUV9GdX0wN5ziSb/ccF2GYi +Q+MS7OxsTEY= -----END CERTIFICATE----- diff --git a/openssl/test/key.pem b/openssl/test/key.pem index a3f80dd975dc3c25f4e35ecf04546c35fc014541..8ee80a8c8bfea5e4122d964a4df8333a0d8a4f2f 100644 --- a/openssl/test/key.pem +++ b/openssl/test/key.pem @@ -1,28 +1,27 @@ ------BEGIN PRIVATE KEY----- -MIIEvwIBADANBgkqhkiG9w0BAQEFAASCBKkwggSlAgEAAoIBAQDYT25igulfh4wb -Pr6X7Vl0PXVjU9CM2OpIDv+erRDqCiA8t2z31r4JrsHbDqZYYykJBslN/S06R0Xp -N3+DAgE1i0e4IgCI+HYZubqhkStUhdbBa5NYLavubIHR4+BrlkAT1KqwWowS6FaK -QQrX5p7UIJ+ZuiCxBJfKXj4RU3vEDB2LrJS1Ev/3aeciYp3AMGG6rN0GkE4NBb9U -KfQobngK9Z3BPSKqDsK8u5dAbLEzwrXtICIG2fo3fxLSN4vgP0isF+L08JgakCfe -MqvigEQlVEI2++eLdD2KQn4YQXme8stUz4j3z+jS8K5jajv7UuLBWIY40nUF9GB0 -VYyPPQF9AgMBAAECggEBAJiYiH20bqA2xk8eF2SkSxvmk15r7U6/Y59L/WZaHvmM -BSvwFk5MzqmUACviDNWDtpookHCVL4fSae5ZeXnZOzMju4eZbRkzdlU1ogSCnbe1 -50dx9XMaXRUItRh1koczaqbSu0tHxVM9VneX5OdkSR3Kmezf0lourEpV66FbbI9i -1F1Q7u6TzldTuPSkQQgV/FHU9DvRPJ6HgSOyVr6Z9Ec0K6odmUXe3wX7+3PbKPtr -JIVQ0wGcc/sImgAr0uS+YbHNWM4qjFAAPteQ/+Df6usSFOkRoD3+XeZrJQQ98C3q -HHW4afaJM0YCsDwn7/E3KiY5fmXwtAHNRuUbsfReP8ECgYEA9JQICyP1N5bZ4uCc -jjTiHLcQX2dHy4dKatqWkV4F52qf4HCZ/pcvPBKNMzM4uTfkCgR+TMzW+A+escvR -8KmaSKmQHT+nUQfMoU2lpZbWSPTF8lLGx+Mf8JAMur0xcmazDB8uDFnvQg+TQY7y -cF6MMWKW3pp+3qI7wRkclXSLZG0CgYEA4mlzuzuB8e7UJ821N+zD8BBYY4EvpUIj -iparwKbM8vAZ1WZssRd+8oHroHJGbjXX4h7gvpUsVadSgs77W9T0zJ+5kJCpVAnO -nKdJkX1Zo1TaIIrRaJhiaPU4hKlnGnko3uv7SlV9PPUtcyBnXElobREmQv6eCmEf -Z7YP4+JoR1ECgYEA3RyrfO7gNYZyq3Mm9kWHGjDCY43q0W0ZcSr3LqrTKZkyuuTx -w8IImQWok9497O1Dg272hBY4ToFIljLPNQUQD5sER/0RFee4LygUlnSce86W2nHN -dk62xHRmnbiHaIbCXjYeGlqAPLf6CC3kroQ7uDYKcWs5Qatn3DYIqnF3x60CgYA/ -plWatUf6s6GA7xua9TzAKFgw4Qh79PP46hKuvjWvtkAM9hZoUqqlklCjcnzKTui5 -8ORNr7IfAkL38yhG0L9hJyYLth9kOL2U3JKaDBs/B4Oq0lu8g9pml0mkQdtyXc1X -ng+u/gmPMX3td5aXIyvwPXn8K4hScqtZhJ1C+0tFgQKBgQDtlBXw3mY3AMwT+wtx -ZiitDk7tAXj7wioCOziTFKkL01UMt4VIkNvQU7RUTcig6PBc0PxU6TZQpncOk/cP -eqQQP0TJGNzIK71EwAL5aFm9o9VoXsrwjVDZnzMr703MyU15QXO76kmxmh+rK5Qy -uldCJliojIW1UW30MXSXK96YXQ== ------END PRIVATE KEY----- +-----BEGIN RSA PRIVATE KEY----- +MIIEpQIBAAKCAQEA1iDxqmqH6cdgEv8pL1Iu0OaFNHaz4feaTtq9cAJqEwS38Rqm +x+3lg4nwkCQ9uSjJ33VC3FusMXUzeu1N9bAet/iMJ5nqS3YJK9jIkI8//sltY90w +OxgUG2gE4RUx2M4uvhHy0Bqva3Ua7rcy7stZ5i/IUqomkOQ/fT+T44QPv2Xus5CD +p5U35COvXDHdVIGGi+xRKEadJHDlhaIqe+9ScfCrZ5eTBcU52SFE2xOlaBX4Rmw5 +26dzMZsQbipr6LAmOh39vw71HWsivXabCBPZTcYc2klTQj5C7bTrec42d2Ex8RLe +Z3pAIiUoxVgNJT9aWLmwvFPHKRda/njwhvxi/wIDAQABAoIBAQC918dqx7hoVBOh +xAfHpJ1NKJPAx90D4no0n0qFHB7fbbeHU5G6f/iUfp+BrB/tIXSZYWU96SjpUHer +7OjJgrQ5d2sLUTKgZK4M6c4oHFkok30gpOI2AksRYU+yHxBqn6JhcZhNWNtd8h1G +t7W4cSHrK0H3yFMY8sQ3Tz7W4Cb2ENIN4wBKeQnmk4k9icG5yz0xLI/vPxqujKij +JWMbk2jNllaUvDgsTAg/MFCzlJH98lzRrX/dhG+q6Rt4S18xac71PMGyUaWduyeC +BHGhHW34361zGQYyeG6eWroTQhvwMHjNxvzA/RiTgHBXV5oRvd9BPPoUS53HYQJO +mzNnfZvBAoGBAPF3VVw+RqG/+OyEkuqE20H35/oSB8tPC6QL/WjWUFwIcSfnkX7H +WmdHBfqCAZlAOqOYgO3iWcgbcOhnggP9J6ssooErt6M7s7hPG/WXwSf0DoCUgtQF +9OrcGNBvwtBMqm82hb8u4IpXUApMYF48MkjbaKSmHU3HQe0sIDese+wlAoGBAOME +YJgtl6t3rcaJ2jzHfEsCTCtCBs2vS9ido73xF3QHTafll/sKMp5bA0mgNhSsphhs +mJCfOl2Cr+0oN90zkumFe4bNIbWQOL/q+HeFwebK5/oWlg/NyvFmMm7LmniFPpBD +NJHqV/ehn8Xuw4LheSG1Bg/aRH5NtoKDcG8+4ZdTAoGAFkTHHoavxOMLdeSUGATA +o8jVH/7hsSJNFIf2iuCY8KPmq6Nzi5mfAL9QEdZDh3qg7c12tnmVhhrhws0o9G04 +Z1Tqd7csbGVpIapKDdA9BA5B+CG6HwudlrtNnotwD/3CChehJgyQsLF0tD5u9MHg +cU+qyuR292FU9yaGohvKIfECgYEAjX7c9fz029rsZSLm85sizV3RO+UbeHgaPhmD +RZBPnfIvZMalw8LHagwwMGO7UYeKvw5wyTN1nXMnVBoNN8I9f2/DXnHc4N3TgUtj +MpwcD03I6QfK4G7UX0HjjUs6LIRgSmqZCZmW2rHSc/wtwBXo+ilqbdcNeevWJeLm +4W/ADCECgYEA7RGbA6qzHtjVS4Nc9rE1tcv4a7p0EvnMXZhIkDZtJqPpkpyOZllm +cTuMCGisw0SEIcSoH1pWRDschbIlOlsn1Mhnb/IczqfHZjb4hmX7Cnlc8WP6TBqI +vma9anlEWW7eIOn5jkY3liQpQ7GJPkCjWuRzne26iV/LIsYj48602Z8= +-----END RSA PRIVATE KEY-----