I was made aware of C2PA in a video where they talked about how to be sure video, images and documents come from the claimed source. And they explained C2PA as going from http to https.
So I did a bit of research and I found the site of the Content Authenticity Initiative and the C2PA wiki.
The one thing I was thinking while going through all the content was, they mention buying a certificate multiple times. But for websites we use Let's Encrypt for years now. There are hosting companies that have build it in their hosting solutions.
So why not use Let's Encrypt to sign video, images and documents.
The Symfony console command
The command assumes it is executed on Linux, and the commands certbot, openssl and c2patool are installed.
use Symfony\Component\Console\Attribute\AsCommand;
use Symfony\Component\Console\Attribute\Argument;
use Symfony\Component\Console\Attribute\Option;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\Process\Process;
#[AsCommand(
name: 'c2pa:sign',
description: 'Sign a file with C2PA using a Let’s Encrypt certificate (manifest as file or JSON string)',
)]
class SignC2paCommand extends Command
{
protected function execute(
InputInterface $input,
OutputInterface $output,
#[Argument(
name: 'domain',
description: 'Domain for which the Let’s Encrypt certificate is issued',
mode: Argument::REQUIRED
)]
string $domain,
#[Argument(
name: 'file',
description: 'Path to the file that should be signed',
mode: Argument::REQUIRED
)]
string $filePath,
#[Option(
name: 'manifest',
shortcut: 'm',
description: 'Path to a JSON manifest file or a raw JSON string (optional)',
mode: Option::VALUE_OPTIONAL
)]
?string $manifestInput = null
): int {
// Make sure the certificate is valid.
$certbot = new Process([
'certbot', 'certonly',
'--standalone',
'-d', $domain,
'--non-interactive',
'--agree-tos',
'--email', "admin@{$domain}"
]);
$certbot->run();
if (!$certbot->isSuccessful()) {
$output->writeln('<error>Certbot failed:</error>');
$output->writeln($certbot->getErrorOutput());
return Command::FAILURE;
}
$liveDir = "/etc/letsencrypt/live/{$domain}";
$privKey = "{$liveDir}/privkey.pem";
// Create C2PA certificate.
$signCert = sys_get_temp_dir() . "/c2pa-signing-{$domain}.crt";
$openssl = new Process([
'openssl', 'req', '-new', '-x509',
'-key', $privKey,
'-out', $signCert,
'-days', '30',
'-subj', "/CN={$domain}"
]);
$openssl->run();
if (!$openssl->isSuccessful()) {
$output->writeln('<error>OpenSSL failed:</error>');
$output->writeln($openssl->getErrorOutput());
return Command::FAILURE;
}
$manifestFile = null; // will hold the path passed to c2patool
if ($manifestInput !== null) {
// If the input points to an existing file, use it directly
if (is_file($manifestInput)) {
$manifestFile = $manifestInput;
} else {
// Assume it is a raw JSON string – validate basic JSON syntax
json_decode($manifestInput);
if (json_last_error() !== JSON_ERROR_NONE) {
$output->writeln('<error>Provided manifest string is not valid JSON.</error>');
return Command::FAILURE;
}
// Write the JSON to a temporary file
$tmp = tempnam(sys_get_temp_dir(), 'c2pa-manifest-');
if ($tmp === false) {
$output->writeln('<error>Failed to create temporary file for manifest.</error>');
return Command::FAILURE;
}
file_put_contents($tmp, $manifestInput);
$manifestFile = $tmp;
}
}
$c2paArgs = [
'c2patool', 'sign',
'--key', $privKey,
'--cert', $signCert,
];
if ($manifestFile !== null) {
$c2paArgs[] = '--manifest';
$c2paArgs[] = $manifestFile;
}
$c2paArgs[] = $filePath;
$c2pa = new Process($c2paArgs);
$c2pa->run();
// Clean up temporary manifest file if we created one
if (isset($tmp) && file_exists($tmp)) {
@unlink($tmp);
}
if (!$c2pa->isSuccessful()) {
$output->writeln('<error>c2patool failed:</error>');
$output->writeln($c2pa->getErrorOutput());
return Command::FAILURE;
}
$output->writeln("<info>{$filePath} signed successfully.</info>");
return Command::SUCCESS;
}
}
This make it possible to sign the supported files with php bin/console c2pa:sign example.com /path/to/photo.jpg -m '{"assertions":[{"label":"c2pa.creator","data":{"name":"Bob"}}]}'.
Conclusion
I still have a lot to learn about C2PA. And I also have questions like how devices and applications are going to handle certificate invalidation?
I think it is good there is an initiative that wants to create file creator/manipulator transparency.
The next step for the AI providers is to attribute the people which work is the base of the generated content.
Top comments (0)