Exemple #1
0
/**
 * 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;
}
Exemple #2
0
/**
 * 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;
}
Exemple #3
0
/**
 * 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()));
}
Exemple #4
0
/**
 * 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());
    }
}
Exemple #5
0
/**
 * @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;
}
Exemple #6
0
/**
 * 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;
}
Exemple #7
0
/**
 * 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;
}
Exemple #8
0
/**
 * 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() );
	}

}
Exemple #9
0
/**
 * 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());
}
Exemple #10
0
/**
 * 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());
            }
        }
    }
}
Exemple #11
0
/**
 * 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) );
}
Exemple #12
0
/**
 * 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
    }
}
Exemple #13
0
/**
 * 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;
}
Exemple #14
0
/**
 * 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;
}
Exemple #15
0
/**
 * 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);
}
Exemple #16
0
/**
 * 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;
}
Exemple #17
0
/**
 * 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;
}
Exemple #18
0
/**
 * 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);
}
Exemple #19
0
/**
 * 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()));
    }
}
Exemple #20
0
digidoc::Conf* digidoc::Conf::getInstance() throw(IOException)
{
    if (INSTANCE == NULL)
    {
        THROW_IOEXCEPTION("Conf is not initialized");
    }
	return INSTANCE;
}
Exemple #21
0
/**
 * 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;
}
Exemple #23
0
/**
 * @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;
}
Exemple #24
0
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;
}
Exemple #25
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);
}
Exemple #26
0
/**
 * 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;
}
Exemple #27
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;
}
Exemple #28
0
/**
 * @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;
}
Exemple #29
0
/**
 * @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;
}
Exemple #30
0
/**
 * 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);
}