/** * Check if X509Cert is signed by trusted issuer * @return 0 or openssl error_code. Get human readable cause with X509_verify_cert_error_string(code) * @throw IOException if error */ int digidoc::X509Cert::verify() const throw(IOException) { X509_STORE_CTX *csc = X509_STORE_CTX_new(); X509_STORE_CTX_scope csct(&csc); if (!csc) THROW_IOEXCEPTION("Failed to create X509_STORE_CTX %s",ERR_reason_error_string(ERR_get_error())); X509_STORE *store = digidoc::X509CertStore::getInstance()->getCertStore(); X509* x = getX509(); X509_scope xt(&x); if(!X509_STORE_CTX_init(csc, store, x, NULL)) THROW_IOEXCEPTION("Failed to init X509_STORE_CTX %s",ERR_reason_error_string(ERR_get_error())); int ok = X509_verify_cert(csc); if(!ok) { int err = X509_STORE_CTX_get_error(csc); X509Cert cause(X509_STORE_CTX_get_current_cert (csc)); std::ostringstream s; s << "Unable to verify " << cause.getSubject(); s << ". Cause: " << X509_verify_cert_error_string(err); switch(err) { case X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY: { IOException e(__FILE__, __LINE__, s.str()); e.setCode( Exception::CertificateIssuerMissing ); throw e; break; } default: THROW_IOEXCEPTION(s.str().c_str()); break; } } return ok; }
/** * Parses X.509 PEM formatted certificate from file. * NB! This struct must be freed using X509_free() function from OpenSSL or * with X509_scope struct. * * @param path PEM formatted X.509 certificate file path. * @return returns certificate parsed from file. * @throws IOException throws exception if the file does not contain X.509 * PEM formatted certificate. */ X509* digidoc::X509Cert::loadX509(const std::string& path) throw(IOException) { // Initialize OpenSSL file. BIO* file = BIO_new(BIO_s_file()); BIO_scope fileScope(&file); if(file == NULL) { THROW_IOEXCEPTION("Failed to open X.509 certificate file '%s': %s", path.c_str(), ERR_reason_error_string(ERR_get_error())); } if(BIO_read_filename(file, path.c_str()) <= 0) { THROW_IOEXCEPTION("Failed to open X.509 certificate file '%s': %s", path.c_str(), ERR_reason_error_string(ERR_get_error())); } // Parse X.509 certificate from file. X509* cert = PEM_read_bio_X509(file, NULL, NULL, NULL); if(cert == NULL) { THROW_IOEXCEPTION("Failed to load X.509 certificate from file '%s': %s", path.c_str(), ERR_reason_error_string(ERR_get_error())); } return cert; }
/** * Add data for digest calculation. After calling <code>getDigest()</code> SHA context * is uninitialized and this method should not be called. * * @param data data to add for digest calculation. * @param length length of the data. * @throws IOException throws exception if update failed. * @see getDigest() */ void digidoc::Digest::update(const unsigned char *data, unsigned long length) throw(IOException) { if(data == NULL) THROW_IOEXCEPTION("Can not update digest value from NULL pointer."); if(!d->digest.empty()) THROW_IOEXCEPTION("Digest is already finalized, can not update it."); int result = 1; switch(d->method) { case NID_sha1: result = SHA1_Update(&d->sha1, static_cast<const void*>(data), length); break; case NID_sha224: result = SHA224_Update(&d->sha256, static_cast<const void*>(data), length); break; case NID_sha256: result = SHA256_Update(&d->sha256, static_cast<const void*>(data), length); break; case NID_sha384: result = SHA384_Update(&d->sha512, static_cast<const void*>(data), length); break; case NID_sha512: result = SHA512_Update(&d->sha512, static_cast<const void*>(data), length); break; default: break; } if(result != 1) THROW_IOEXCEPTION("Failed to update %s digest value: %s", getName().c_str(), ERR_reason_error_string(ERR_get_error())); }
/** * Copies file from source <code>srcPath</code> to destination <code>destPath</code>. * * @param srcPath source full file path. * @param destPath destination full file path. * @param overwrite whether to overwrite existing file. * @throws IOException exception is thrown if overwrite flag is set to false and destination file already exists. * Or the file copy operation failed. */ void digidoc::util::File::copyFile(const std::string& srcPath, const std::string& destPath, bool overwrite) throw(IOException) { if(!fileExists(srcPath)) { THROW_IOEXCEPTION("Source file '%s' does not exist.", srcPath.c_str()); } if(!overwrite && fileExists(destPath)) { THROW_IOEXCEPTION("Destination file exists '%s' can not copy to there. Overwrite flag is set to false.", destPath.c_str()); } // Copy file. std::ifstream ifs(encodeName(srcPath).c_str(), std::ios::binary); std::ofstream ofs(encodeName(destPath).c_str(), std::ios::binary | std::ios::trunc); ofs << ifs.rdbuf(); ifs.close(); ofs.close(); if(ifs.fail() || ofs.fail()) { THROW_IOEXCEPTION("Failed to copy file '%s' to '%s'.", srcPath.c_str(), destPath.c_str()); } }
/** * @return Extracts RSA exponent from X.509 certificate and returns it. * @throws IOException throws exception if the RSA exponent extraction failed. */ std::vector<unsigned char> digidoc::X509Cert::getRsaExponent() const throw(IOException) { EVP_PKEY* pubKey = getPublicKey(); // Get size of the RSA exponent. int bufSize = BN_num_bytes(pubKey->pkey.rsa->e); if(bufSize <= 0) { EVP_PKEY_free(pubKey); THROW_IOEXCEPTION("Failed to extract RSA exponent."); } // Allocate memory for the RSA exponent. std::vector<unsigned char> rsaExponent(bufSize, 0); // Extract RSA exponent. if(BN_bn2bin(pubKey->pkey.rsa->e, &rsaExponent[0]) <= 0) { EVP_PKEY_free(pubKey); THROW_IOEXCEPTION("Failed to extract RSA exponent."); } EVP_PKEY_free(pubKey); return rsaExponent; }
/** * Signs the digest with provided RSA private key. * * @param digestMethod digest method (e.g NID_sha1 for SHA1, see openssl/obj_mac.h). * @param digest digest value, this value is signed with the private RSA key. * @return returns signature. * @throws IOException */ std::vector<unsigned char> digidoc::RSACrypt::sign(const Signer::Digest& digest) throw(IOException) { // Calculate memory needed for signature. unsigned int blockSize = RSA_size(privateKey); unsigned int neededSize = blockSize; if(digest.length > blockSize) { if(digest.length % blockSize == 0) neededSize = digest.length; else neededSize = ((digest.length / blockSize) + 1) * blockSize; } // Allocate memory for the signature. std::vector<unsigned char> signature(neededSize, 0); // Sign the digest with private RSA key. unsigned int signatureLength = 0; int result = RSA_sign(digest.type, digest.digest, digest.length, &signature[0], &signatureLength, privateKey); // Check that signing was successful. if(result != 1) { THROW_IOEXCEPTION("Failed to sign the digest: %s", ERR_reason_error_string(ERR_get_error())); } if(signatureLength != neededSize) { THROW_IOEXCEPTION("Failed to sign the digest."); } return signature; }
/** * Converts individual X.509 subject entry to string. * * @param ln Long name of the requested entry (see openssl/objects.h) * @return subject name entry converted to string. * @throws IOException exception is throws if the conversion failed. */ std::string digidoc::X509Cert::getSubjectInfo(const std::string& ln) const throw(IOException) { X509_NAME* name = X509_get_subject_name(cert); if(name == NULL) { THROW_IOEXCEPTION("Failed to convert X.509 certificate subject: %s", ERR_reason_error_string(ERR_get_error())); } int idx = X509_NAME_get_index_by_NID(name, OBJ_ln2nid(ln.c_str()), -1); if(idx < 0) { THROW_IOEXCEPTION("Failed to retrieve X.509 certificate info: field '%s' not found", ln.c_str()); } X509_NAME_ENTRY *entry = X509_NAME_get_entry(name, idx); if(!entry) { THROW_IOEXCEPTION("Failed to convert X.509 certificate field: %s", ERR_reason_error_string(ERR_get_error())); } ASN1_STRING *asnstr = X509_NAME_ENTRY_get_data(entry); unsigned char *data = NULL; int len = ASN1_STRING_to_UTF8(&data, asnstr); if(len < 0) { THROW_IOEXCEPTION("Failed to convert X.509 certificate field: %s", ERR_reason_error_string(ERR_get_error())); } std::string result(reinterpret_cast<const char *>(data)); OPENSSL_free(data); return result; }
/** * Moves file from source <code>srcPath</code> to destination <code>destPath</code>. * * @param srcPath source full file path. * @param destPath destination full file path. * @param overwrite whether to overwrite existing file. * @throws IOException exception is thrown if overwrite flag is set to false and destination file already exists. * Or the file move operation failed. */ void digidoc::util::File::moveFile(const std::string& srcPath, const std::string& destPath, bool overwrite) throw(IOException) { if(!fileExists(srcPath)) { THROW_IOEXCEPTION("Source file '%s' does not exist.", srcPath.c_str()); } if(!overwrite && fileExists(destPath)) { THROW_IOEXCEPTION("Destination file exists '%s' can not move to there. Overwrite flag is set to false.", destPath.c_str()); } f_string _srcPath = encodeName(srcPath); f_string _destPath = encodeName(destPath); int result = f_rename(_srcPath.c_str(), _destPath.c_str()); if ( result != 0 ) { // -=K=-: copy and remove source should work as move between different partitions copyFile( srcPath, destPath, overwrite ); result = f_remove( _srcPath.c_str() ); } if ( result != 0 ) { // -=K=-: suceeded to copy, failed to remove. Should we throw or warn? WARN( "Failed to remove source file '%s' when moving it to '%s'.", _srcPath.c_str(), _destPath.c_str() ); } }
/** * Reads and parses container mimetype. Checks that the mimetype is supported. * * @param path path to container directory. * @throws IOException exception is thrown if there was error reading mimetype file from disk. * @throws BDocException exception is thrown if the parsed mimetype is incorrect. */ void digidoc::BDoc::readMimetype(const std::string &path) throw(IOException, BDocException) { DEBUG("BDoc::readMimetype(path = '%s')", path.c_str()); // Read mimetype from file. std::string fileName = util::File::path(path, "mimetype"); std::ifstream ifs(util::File::encodeName(fileName).c_str(), std::ios::binary); unsigned char bom[] = { 0, 0, 0 }; ifs.read((char*)bom, sizeof(bom)); // Contains UTF-16 BOM if((bom[0] == 0xFF && bom[1] == 0xEF) || (bom[0] == 0xEF && bom[1] == 0xFF)) THROW_IOEXCEPTION("Mimetype file must be UTF-8 format.", fileName.c_str()); // does not contain UTF-8 BOM reset pos if(!(bom[0] == 0xEF && bom[1] == 0xBB && bom[2] == 0xBF)) ifs.seekg(0, std::ios::beg); std::string mimetype; ifs >> mimetype; ifs.close(); if(ifs.fail()) THROW_IOEXCEPTION("Failed to read mimetype file from '%s'.", fileName.c_str()); // Check that mimetype version is correct. DEBUG("mimetype = '%s'", mimetype.c_str()); if(getMimeType() != mimetype) THROW_BDOCEXCEPTION("Incorrect mimetype '%s', expecting '%s'", mimetype.c_str(), getMimeType().c_str()); }
/** * Tries to initialize XmlConf by using file defined in DIGIDOCPP_OVERRIDE_CONF environment variable. * If this is undefined, tries to load configuration from defined Default and user configuration file */ digidoc::XmlConf::XmlConf() throw(IOException) { if (!DEFAULT_CONF_LOC.size()) THROW_IOEXCEPTION("XmlConf not initialized!"); if(util::File::fileExists(DEFAULT_CONF_LOC)) init(DEFAULT_CONF_LOC); else THROW_IOEXCEPTION("Error loading xml configuration from '%s' file",DEFAULT_CONF_LOC.c_str()); if( !getenv("DIGIDOCPP_OVERRIDE_CONF") && util::File::fileExists(USER_CONF_LOC)) { try { init(USER_CONF_LOC); } catch(const IOException &) { // remove invalid user home config (wrong schema location, etc.) try { util::File::removeFile(USER_CONF_LOC); } catch(const IOException &) { THROW_IOEXCEPTION("Failed to remove invalid user home configuration '%s' file",USER_CONF_LOC.c_str()); } } } }
/** * Gets configuration file schema location with full path. * @throws IOException exception is thrown if failed to parse schema location from default conf file. * @return returns configuration file schema location. */ std::string digidoc::XmlConf::getConfSchemaLocation() throw(IOException) { xml_schema::ErrorHandler *errH = NULL; xml_schema::dom::auto_ptr< xercesc::DOMDocument > domDoc; try { //Parse default configuration file into a DOM document domDoc = ::xsd::cxx::xml::dom::parse< char > ( DEFAULT_CONF_LOC, *errH, xml_schema::Properties (), xml_schema::Flags::dont_initialize ); } catch (...) { THROW_IOEXCEPTION("Failed to parse %s into DOMDocument", DEFAULT_CONF_LOC.c_str()); } //Get access to root element xercesc::DOMElement* root = domDoc->getDocumentElement(); //Get schema location atributes. const XMLCh* xsl = root->getAttributeNS ( xercesc::SchemaSymbols::fgURI_XSI, xercesc::SchemaSymbols::fgXSI_NONAMESPACESCHEMALOCACTION); if (xsl == NULL) THROW_IOEXCEPTION("Failed to parse schema location in: %s", DEFAULT_CONF_LOC.c_str()); return digidoc::util::File::path ( getDefaultConfDir(), ::xsd::cxx::xml::transcode<char> (xsl) ); }
/** * Sets Default (global) configuration file path in DEFAULT_CONF_LOC variable. */ void digidoc::XmlConf::setDefaultConfPath() throw(IOException) { char * overrideConf = getenv( "DIGIDOCPP_OVERRIDE_CONF" ); if (overrideConf != NULL) //if there is environment variable defined, use this conf instead of others { if(util::File::fileExists(overrideConf)) DEFAULT_CONF_LOC = overrideConf; else THROW_IOEXCEPTION("Error loading override xml configuration from '%s' file",overrideConf); } else { #ifdef _WIN32 HKEY hkey; DWORD dwSize, dwRet; TCHAR tcConfPath[MAX_PATH]; //Open Registry to get path for default configuration file if(RegOpenKeyEx(HKEY_LOCAL_MACHINE, TEXT(DIGIDOCPP_PATH_REGISTRY_KEY), 0, KEY_QUERY_VALUE, &hkey)==ERROR_SUCCESS) { dwSize = MAX_PATH * sizeof(TCHAR); dwRet = RegQueryValueEx(hkey, TEXT("ConfigFile"), NULL, NULL, (LPBYTE)tcConfPath, &dwSize); RegCloseKey(hkey); if (dwRet == ERROR_SUCCESS) DEFAULT_CONF_LOC = digidoc::util::File::decodeName(tcConfPath); else //if couldn't open regkey value THROW_IOEXCEPTION("Failed to open registry key \"%s\" ConfigFile value ", DIGIDOCPP_PATH_REGISTRY_KEY); } else //if key doesn't exist THROW_IOEXCEPTION("Failed to read registry key \"%s\"", DIGIDOCPP_PATH_REGISTRY_KEY); #else DEFAULT_CONF_LOC = DIGIDOCPP_CONFIG_DIR "/digidocpp.conf"; #endif } }
/** * Converts X509_NAME struct to string. * * @param name X509_NAME struct that is converted to string. * @return converted value of X509_NAME. * @throws IOException throws exception if conversion failed. */ std::string digidoc::X509Cert::toString(X509_NAME* name) throw(IOException) { BIO* mem = BIO_new(BIO_s_mem()); BIO_scope memScope(&mem); if(mem == NULL) { THROW_IOEXCEPTION("Failed to allocate memory for X509_NAME conversion: %s", ERR_reason_error_string(ERR_get_error())); } // Convert the X509_NAME struct to string. if(X509_NAME_print_ex(mem, name, 0, XN_FLAG_RFC2253) < 0) { THROW_IOEXCEPTION("Failed to convert X509_NAME struct to string: %s", ERR_reason_error_string(ERR_get_error())); } // Read the converted string from buffer. char buf[128]; int bytesRead; std::string str; while((bytesRead = BIO_gets(mem, &buf[0], sizeof(buf))) > 0) { str.append(buf); } return str; }
/** * Creates BDoc container manifest file and returns its path. * * Note: If non-ascii characters are present in XML data, we depend on the LANG variable to be set properly * (see iconv --list for the list of supported encoding values for libiconv). * * * @return returns created manifest file path. * @throws IOException exception is thrown if manifest file creation failed. */ std::string digidoc::BDoc::createManifest() throw(IOException) { DEBUG("digidoc::BDoc::createManifest()"); std::string fileName = util::File::tempFileName(); try { manifest::Manifest manifest; // Add container file entry with mimetype. manifest.file_entry().push_back(manifest::File_entry("/", getMimeType())); // Add documents with mimetypes. for(std::vector<Document>::const_iterator iter = documents.begin(); iter != documents.end(); iter++) { manifest::File_entry fileEntry(util::File::fileName(iter->getPath()), iter->getMediaType()); manifest.file_entry().push_back(fileEntry); } // Add signatures with mimetypes. unsigned int i = 0; for(std::vector<Signature*>::const_iterator iter = signatures.begin(); iter != signatures.end(); iter++) { manifest::File_entry fileEntry(util::String::format("META-INF/signature%u.xml", i++), (*iter)->getMediaType()); manifest.file_entry().push_back(fileEntry); } // Serialize XML to file. xml_schema::NamespaceInfomap map; map["manifest"].name = MANIFEST_NAMESPACE; DEBUG("Serializing manifest XML to '%s'", fileName.c_str()); // all XML data must be in UTF-8 std::ofstream ofs(digidoc::util::File::fstreamName(fileName).c_str()); manifest::manifest(ofs, manifest, map, "", xml_schema::Flags::dont_initialize); ofs.close(); if(ofs.fail()) { THROW_IOEXCEPTION("Failed to create manifest XML file to '%s'.", fileName.c_str()); } } catch(const xml_schema::Exception& e) { std::ostringstream oss; oss << e; THROW_IOEXCEPTION("Failed to create manifest XML file. Error: %s", oss.str().c_str()); } return fileName; }
/** * Checks that file is a file and it exists, if the file exists returns its size in bytes. * * @param path full path of the file. * @return size of the file in bytes. * @throws IOException throws exception if the file does not exists. */ unsigned long digidoc::util::File::fileSize(const std::string& path) throw(IOException) { f_statbuf fileInfo; f_string _path = encodeName(path); if(f_stat(_path.c_str(), &fileInfo) != 0) THROW_IOEXCEPTION("File '%s' does not exist.", _path.c_str()); if((fileInfo.st_mode & S_IFMT) == S_IFDIR) THROW_IOEXCEPTION("'%s' is not a file.", _path.c_str()); if (fileInfo.st_size < 0) THROW_IOEXCEPTION("Failed to get size for file '%s'.", _path.c_str()); return static_cast<unsigned long>(fileInfo.st_size); }
/** * Parses X.509 PEM formatted certificates from file. The file can contain multiple * certificates. You can just use 'cat' command in linux to add multiple PEM formatted * X.509 certificates to one file (e.g. <code>cat cert1.pem cert2.pem > certs.pem</code>). * NB! This struct must be freed using sk_X509_free() function from OpenSSL or * with X509Stack_scope struct. * * @param path PEM formatted X.509 certificates file path. * @return returns stack of parsed X.509 certificates. * @throws IOException throws exception if the file does not contain X.509 * PEM formatted certificate(s). */ STACK_OF(X509)* digidoc::X509Cert::loadX509Stack(const std::string& path) throw(IOException) { // Create an empty X.509 stack. STACK_OF(X509)* stack = sk_X509_new_null(); if(stack == NULL) { THROW_IOEXCEPTION("Failed to create X.509 certificate stack."); } // Initialize OpenSSL file. BIO* file = BIO_new(BIO_s_file()); BIO_scope fileScope(&file); if(file == NULL) { THROW_IOEXCEPTION("Failed to open X.509 certificates file '%s': %s", path.c_str(), ERR_reason_error_string(ERR_get_error())); } // Open file, which can contain multiple X.509 certificates. if(BIO_read_filename(file, path.c_str()) <= 0) { THROW_IOEXCEPTION("Failed to open X.509 certificates file '%s': %s", path.c_str(), ERR_reason_error_string(ERR_get_error())); } // Read certificates info from the file. STACK_OF(X509_INFO)* certsInfo = PEM_X509_INFO_read_bio(file, NULL, NULL, NULL); if(certsInfo == NULL) { THROW_IOEXCEPTION("Failed to read X.509 certificates from file '%s': %s", path.c_str(), ERR_reason_error_string(ERR_get_error())); } // Put all found certificates to the stack. for(int i = 0; i < sk_X509_INFO_num(certsInfo); i++) { X509_INFO* xi = sk_X509_INFO_value(certsInfo, i); if(xi->x509 != NULL) { sk_X509_push(stack, xi->x509); xi->x509 = NULL; } } // Release resources. sk_X509_INFO_pop_free(certsInfo, X509_INFO_free); return stack; }
/** * Calculate message digest. SHA context will be invalid after this call. * For calculating an other digest you must create new SHA1Digest class. * * @return returns the calculated digest. * @throws IOException throws exception if update failed. */ std::vector<unsigned char> digidoc::Digest::getDigest() throw(IOException) { // If digest is already calculated return it. if(!d->digest.empty()) return d->digest; int result = 1; unsigned char *buf = new unsigned char[getSize()]; switch(d->method) { case NID_sha1: result = SHA1_Final(buf, &d->sha1); break; case NID_sha224: result = SHA224_Final(buf, &d->sha256); break; case NID_sha256: result = SHA256_Final(buf, &d->sha256); break; case NID_sha384: result = SHA384_Final(buf, &d->sha512); break; case NID_sha512: result = SHA512_Final(buf, &d->sha512); break; default: break; } if(result != 1) { delete[] buf; THROW_IOEXCEPTION("Failed to create %s digest: %s", getName().c_str(), ERR_reason_error_string(ERR_get_error())); } for(unsigned int i = 0; i < getSize(); i++) d->digest.push_back(buf[i]); delete[] buf; return d->digest; }
/** * Set OCSP connection URL. * * @param url full OCSP URL (e.g. http://www.openxades.org/cgi-bin/ocsp.cgi). * @throws IOException exception is thrown if provided OCSP URL is in incorrect format. */ void digidoc::OCSP::setUrl( const std::string& _url ) throw(IOException) { url = _url; // Parse OCSP connection URL. char *_host = NULL, *_port = NULL, *_path = NULL; int sslFlag = 0; if(!OCSP_parse_url(const_cast<char*>(url.c_str()), &_host, &_port, &_path, &sslFlag)) THROW_IOEXCEPTION("Incorrect OCSP URL provided: '%s'.", url.c_str()); ssl = sslFlag != 0; connhost = _host ? _host : ""; connport = _port ? _port : ""; // proxy host digidoc::Conf *c = digidoc::Conf::getInstance(); if(!c->getProxyHost().empty()) { connhost = c->getProxyHost(); connport = c->getProxyPort(); } host = connhost; if(!connport.empty()) host += ":" + connport; OPENSSL_free(_host); OPENSSL_free(_port); OPENSSL_free(_path); }
/** * Creates X509 certificate from the provider DER encoded bytes. * * @param bytes X509 certificate in DER encoding. * @throws IOException throws exception if X509 certificate parsing failed. */ digidoc::X509Cert::X509Cert(std::vector<unsigned char> bytes) throw(IOException) : cert(NULL) { if(bytes.empty()) { THROW_IOEXCEPTION("No bytes given to parse X509."); } // Parse certificate from DER formatted buffer. const unsigned char* pBytes = reinterpret_cast<const unsigned char*>(&bytes[0]); d2i_X509(&cert, &pBytes, bytes.size()); if(cert == NULL) { THROW_IOEXCEPTION("Failed to parse X509 certificate from bytes given: %s", ERR_reason_error_string(ERR_get_error())); } }
digidoc::Conf* digidoc::Conf::getInstance() throw(IOException) { if (INSTANCE == NULL) { THROW_IOEXCEPTION("Conf is not initialized"); } return INSTANCE; }
/** * Converts individual X.509 issuer entry to string. * * @param ln long name of the requested entry (see openssl/objects.h) * @return issuer name entry converted to string. * @throws IOException exception is throws if the conversion failed. */ std::string digidoc::X509Cert::getIssuerInfo(const std::string& ln) const throw(IOException) { char buf[1024]; X509_NAME* name = X509_get_issuer_name(cert); if(name == NULL) { THROW_IOEXCEPTION("Failed to convert X.509 certificate issuer: %s", ERR_reason_error_string(ERR_get_error())); } if(X509_NAME_get_text_by_NID(name, OBJ_ln2nid(ln.c_str()), buf, 1024) < 0) { THROW_IOEXCEPTION("Failed to retrieve X.509 certificate info: field '%s' not found", ln.c_str()); } return std::string(buf); }
/** * @return returns the X.509 certificate store implementation. */ digidoc::X509CertStore* digidoc::X509CertStore::getInstance() throw(IOException) { if (INSTANCE == NULL) { THROW_IOEXCEPTION("X509CertStore is not initialized"); } return INSTANCE; }
/** * @return returns temporary filename. */ std::string digidoc::util::File::tempFileName() { #ifdef _WIN32 // requires TMP environment variable to be set wchar_t *fileName = _wtempnam(0, 0); // TODO: static buffer, not thread-safe if ( !fileName ) THROW_IOEXCEPTION("Failed to create a temporary file name."); #else char *fileName = tempnam(0, 0); if ( !fileName ) THROW_IOEXCEPTION("Failed to create a temporary file name."); #endif std::string path = decodeName(fileName); free(fileName); tempFiles.push(path); return path; }
bool digidoc::X509Cert::isValid() const throw(IOException) { int notBefore = X509_cmp_current_time(cert->cert_info->validity->notBefore); int notAfter = X509_cmp_current_time(cert->cert_info->validity->notAfter); if(notBefore == 0 || notAfter == 0) THROW_IOEXCEPTION("Failed to validate cert",ERR_reason_error_string(ERR_get_error())); return notBefore < 0 && notAfter > 0; }
/** * Converts X.509 subject to string. * * @return issuer name converted to string. * @throws IOException exception is throws if the conversion failed. */ std::string digidoc::X509Cert::getSubject() const throw(IOException) { X509_NAME* subject = X509_get_subject_name(cert); if(!subject) THROW_IOEXCEPTION("Failed to convert X.509 certificate subject: %s", ERR_reason_error_string(ERR_get_error())); return toString(subject); }
/** * Converts digest method URI to OpenSSL method id (e.g. 'http://www.w3.org/2000/09/xmldsig#sha1' to NID_sha1, * see openssl/obj_mac.h) * For available method URIs see: * <li> * <ul><b>W3C XML Encryption Syntax and Processing</b> (10 December 2005) http://www.w3.org/TR/xmlenc-core/</ul> * <ul><b>RFC 4051</b> http://www.ietf.org/rfc/rfc4051.txt</ul> * </li> * * @param methodUri digest method URI (e.g. 'http://www.w3.org/2000/09/xmldsig#sha1' for SHA1). * @return returns digest OpenSSL method id. * @throws IOException throws exception if digest method is not supported. */ int digidoc::Digest::toMethod(const std::string &methodUri) throw(IOException) { if ( methodUri == URI_SHA1 || methodUri == URI_RSA_SHA1 ) return NID_sha1; if ( methodUri == URI_SHA224 || methodUri == URI_RSA_SHA224 ) return NID_sha224; if ( methodUri == URI_SHA256 || methodUri == URI_RSA_SHA256 ) return NID_sha256; if ( methodUri == URI_SHA384 || methodUri == URI_RSA_SHA384 ) return NID_sha384; if ( methodUri == URI_SHA512 || methodUri == URI_RSA_SHA512 ) return NID_sha512; THROW_IOEXCEPTION( "Digest method URI '%s' is not supported.", methodUri.c_str() ); return 0; }
/** * Creates a copy of the X509 certificate. * * @param cert X509 certificate to be copied. * @return returns copy of X509. * @throws IOException throws exception if the X509 cert structure copy fails. */ X509* digidoc::X509Cert::copyX509(X509* cert) throw(IOException) { X509* copy = X509_dup(cert); if(copy == NULL) { THROW_IOEXCEPTION("Failed to copy X509 certificate: %s", ERR_reason_error_string(ERR_get_error())); } return copy; }
/** * @return returns X.509 certificates public key. * @throws IOException throws exception if public key is missing. */ EVP_PKEY* digidoc::X509Cert::getPublicKey() const throw(IOException) { EVP_PKEY* pubKey = X509_get_pubkey(cert); if((pubKey == NULL) || (pubKey->type != EVP_PKEY_RSA)) { EVP_PKEY_free(pubKey); THROW_IOEXCEPTION("Unable to load RSA public Key: %s", ERR_reason_error_string(ERR_get_error())); } return pubKey; }
/** * @return returns X.509 certificate serial number. * @throws IOException exception is thrown if the serial is incorrect. */ long digidoc::X509Cert::getSerial() const throw(IOException) { long serial = ASN1_INTEGER_get(X509_get_serialNumber(cert)); if(serial <= 0) { THROW_IOEXCEPTION("Failed to read certificate serial number from X.509 certificate: %s", ERR_reason_error_string(ERR_get_error())); } return serial; }
/** * Converts X.509 issuer name to string. * * @return issuer name converted to string. * @throws IOException exception is throws if the conversion failed. */ std::string digidoc::X509Cert::getIssuerName() const throw(IOException) { X509_NAME* issuerName = X509_get_issuer_name(cert); if(issuerName == NULL) { THROW_IOEXCEPTION("Failed to convert X.509 certificate issuer name: %s", ERR_reason_error_string(ERR_get_error())); } return toString(issuerName); }