static off_t get_sig_offset(xar_t x) { off_t signedDataOffset = 0; xar_signature_t sig = xar_signature_first(x); xar_signature_copy_signed_data(sig,NULL,NULL,NULL,NULL,&signedDataOffset); signedDataOffset += xar_get_heap_offset(x); return signedDataOffset; }
bool InstallChecker::verifyPackage( const QString &filePath, bool ) { QProcess proc; proc.start( "hdiutil", QStringList() << "verify" << filePath ); proc.waitForFinished(); if( proc.exitCode() ) return false; QString path = mountPackage( filePath ); if( path.isEmpty() ) return false; xar_t xar = xar_open( path.toUtf8().constData(), 0 ); if( !xar ) return false; QSslCertificate cert; xar_signature_t sig = xar_signature_first( xar ); int32_t count = xar_signature_get_x509certificate_count( sig ); for( int32_t i = 0; i < count; ++i ) { uint32_t size = 0; const uint8_t *data = 0; if( xar_signature_get_x509certificate_data( sig, i, &data, &size ) ) continue; QSslCertificate c( QByteArray( (const char*)data, size ), QSsl::Der ); #if QT_VERSION >= 0x050000 QString cn = c.subjectInfo( QSslCertificate::CommonName ).value(0); #else QString cn = c.subjectInfo( QSslCertificate::CommonName ); #endif if( cn == "Estonian Informatics Centre" || cn == "Developer ID Installer: Riigi Infosüsteemi Amet" ) cert = c; } if( cert.isNull() ) { xar_close( xar ); return false; } uint8_t *data = 0, *signature = 0; uint32_t dataSize = 0, signatureSize = 0; off_t offset = 0; if( xar_signature_copy_signed_data( sig, &data, &dataSize, &signature, &signatureSize, &offset ) ) { xar_close( xar ); return false; } int result = RSA_verify( NID_sha1, data, dataSize, signature, signatureSize, (RSA*)cert.publicKey().handle() ); xar_close( xar ); free( data ); free( signature ); return result; }
static void extract_data_to_sign(const char *filename) { xar_signature_t sig; off_t signatureOffset; FILE *file; xar_t x; int i; uint32_t dataToSignOffset = 0; uint32_t dataToSignSize = 0; char *buffer = NULL; const char *value; // find signature stub x = xar_open(filename, READ); if ( x == NULL ) { fprintf(stderr, "Could not open %s to extract data to sign!\n", filename); exit(1); } sig = xar_signature_first(x); if ( !sig ) { fprintf(stderr, "No signatures found to extract data from.\n"); exit(E_NOSIG); } // locate data to sign if( 0 != xar_prop_get((xar_file_t)x, "checksum/offset" ,&value) ){ fprintf(stderr, "Could not locate checksum/offset in archive.\n"); exit(1); } dataToSignOffset = xar_get_heap_offset(x); dataToSignOffset += strtoull(value, (char **)NULL, 10); if( 0 != xar_prop_get((xar_file_t)x, "checksum/size" ,&value) ){ fprintf(stderr, "Could not locate checksum/size in archive.\n"); exit(1); } dataToSignSize = strtoull(value, (char **)NULL, 10); // get signature offset (inject signature here) xar_signature_copy_signed_data(sig, NULL, NULL, NULL, NULL, &signatureOffset); signatureOffset += xar_get_heap_offset(x); xar_close(x); // now get data to be signed, using offset and size file = fopen(filename, "r"); if (!file) { fprintf(stderr, "Could not open %s for reading data to sign!\n", filename); exit(1); } fseek(file, dataToSignOffset, SEEK_SET); buffer = malloc(dataToSignSize); i = fread(buffer, dataToSignSize, 1, file); if (i != 1) { fprintf(stderr, "Failed to read data to sign from %s!\n", filename); exit(1); } fclose(file); // save data to sign file = fopen(DataToSignDumpPath, "w"); if (!file) { fprintf(stderr, "Could not open %s for saving data to sign!\n", DataToSignDumpPath); exit(1); } i = fwrite(buffer, dataToSignSize, 1, file); if (i != 1) { fprintf(stderr, "Failed to write data to sign to %s (fwrite() returned %i)!\n", DataToSignDumpPath, i); exit(1); } fclose(file); // save signature offset file = fopen(SigOffsetDumpPath, "w"); if (!file) { fprintf(stderr, "Could not open %s for saving signature offset!\n", SigOffsetDumpPath); exit(1); } i = fprintf(file, "%lli\n", signatureOffset); if (i < 0) { fprintf(stderr, "Failed to write signature offset to %s (fprintf() returned %i)!\n", SigOffsetDumpPath, i); exit(1); } fclose(file); free(buffer); }