У меня был случай, когда мне нужно было создать функцию подписи PDF-файлов с помощью ключа безопасности. Для этого я использую Yubikey 5A и его библиотеку yubico-piv-tool. Я собрал код, используя различные ресурсы, но до сих пор не могу получить конечный результат.
void signPDF(const char* pdfFilePath, const char* yubikeyPIN) {
// Open PDF file
HPDF_Doc pdf = HPDF_New(error_handler, NULL);
if (!pdf) {
fprintf(stderr, "Error: Cannot create PDF object\n");
return;
}
// Add a page to the document
HPDF_Page page = HPDF_AddPage(pdf);
// Set the font and size
HPDF_Font font = HPDF_GetFont(pdf, "Helvetica", NULL);
HPDF_Page_SetFontAndSize(page, font, 24);
// Write some text
HPDF_Page_BeginText(page);
HPDF_Page_TextOut(page, 50, 700, "Not so Random!");
HPDF_Page_EndText(page);
// Save PDF content to stream
if (HPDF_OK != HPDF_SaveToStream(pdf)) {
fprintf(stderr, "Error: Cannot save PDF to stream\n");
HPDF_Free(pdf);
return;
}
// Get the size of the stream
HPDF_UINT32 contentLen = HPDF_GetStreamSize(pdf);
// Allocate memory for the content
HPDF_BYTE *content = (HPDF_BYTE *)malloc(contentLen);
// Perform signing operation using YubiKey's PIV
ykpiv_state *state;
if (ykpiv_init(&state, 0) != YKPIV_OK) {
fprintf(stderr, "Error: Cannot initialize YubiKey PIV\n");
return;
}
ykpiv_rc res = ykpiv_connect(state, NULL);
if (res != YKPIV_OK) {
fprintf(stderr, "Error: ykpiv_connect failed with code %d\n", res);
return;
}
int tries;
res = ykpiv_verify(state, yubikeyPIN, &tries);
if (res != YKPIV_OK) {
fprintf(stderr, "Error: Cannot authenticate with YubiKey\n");
return;
}
size_t signatureLen = YKPIV_MAX_SIGNATURE_SIZE;
unsigned char signature[YKPIV_MAX_SIGNATURE_SIZE];
res =
ykpiv_sign_data(state, content, contentLen, signature, &signatureLen,
YKPIV_ALGO_ECCP256, YKPIV_KEY_SIGNATURE);
if (res != YKPIV_OK) {
fprintf(stderr, "Error: Cannot sign PDF content. Error code: %d\n", res);
ykpiv_done(state);
HPDF_Free(pdf);
return;
}
// Save the signed PDF file
if (HPDF_SaveToFile(pdf, "signed_example.pdf") != HPDF_OK) {
fprintf(stderr, "Error: Cannot save signed PDF file.\n");
return;
}
printf("PDF file signed successfully.\n");
}void signPDF(const char* pdfFilePath, const char* yubikeyPIN) {
// Open PDF file
HPDF_Doc pdf = HPDF_New(error_handler, NULL);
if (!pdf) {
fprintf(stderr, "Error: Cannot create PDF object\n");
return;
}
// Add a page to the document
HPDF_Page page = HPDF_AddPage(pdf);
// Set the font and size
HPDF_Font font = HPDF_GetFont(pdf, "Helvetica", NULL);
HPDF_Page_SetFontAndSize(page, font, 24);
// Write some text
HPDF_Page_BeginText(page);
HPDF_Page_TextOut(page, 50, 700, "Not so Random!");
HPDF_Page_EndText(page);
// Save PDF content to stream
if (HPDF_OK != HPDF_SaveToStream(pdf)) {
fprintf(stderr, "Error: Cannot save PDF to stream\n");
HPDF_Free(pdf);
return;
}
// Get the size of the stream
HPDF_UINT32 contentLen = HPDF_GetStreamSize(pdf);
// Allocate memory for the content
HPDF_BYTE *content = (HPDF_BYTE *)malloc(contentLen);
// Perform signing operation using YubiKey's PIV
ykpiv_state *state;
if (ykpiv_init(&state, 0) != YKPIV_OK) {
fprintf(stderr, "Error: Cannot initialize YubiKey PIV\n");
return;
}
ykpiv_rc res = ykpiv_connect(state, NULL);
if (res != YKPIV_OK) {
fprintf(stderr, "Error: ykpiv_connect failed with code %d\n", res);
return;
}
int tries;
res = ykpiv_verify(state, yubikeyPIN, &tries);
if (res != YKPIV_OK) {
fprintf(stderr, "Error: Cannot authenticate with YubiKey\n");
return;
}
size_t signatureLen = YKPIV_MAX_SIGNATURE_SIZE;
unsigned char signature[YKPIV_MAX_SIGNATURE_SIZE];
res =
ykpiv_sign_data(state, content, contentLen, signature, &signatureLen,
YKPIV_ALGO_ECCP256, YKPIV_KEY_SIGNATURE);
if (res != YKPIV_OK) {
fprintf(stderr, "Error: Cannot sign PDF content. Error code: %d\n", res);
ykpiv_done(state);
HPDF_Free(pdf);
return;
}
// Save the signed PDF file
if (HPDF_SaveToFile(pdf, "signed_example.pdf") != HPDF_OK) {
fprintf(stderr, "Error: Cannot save signed PDF file.\n");
return;
}
printf("PDF file signed successfully.\n");
}
По сути, код создает документ с одной страницей (это не совсем важно, поскольку, когда я разберусь с подписью, я смогу загрузить PDF-документ прямо из хранилище) и подписывает его содержимое с помощью закрытого ключа в Yubikey. Но моя проблема в том, что я не могу понять, как добавить этот подписанный контент в правильные диапазоны байтов в PDF.
Я пробовал использовать библиотеку PoDoFo, но, похоже, это необходимо работайте только с заранее доступным закрытым ключом, что сводит на нет всю цель, поскольку ключ в любом случае не следует вынимать из YubiKey. Я пытался разобраться в том, как подписываются PDF-файлы, но создание функциональности с нуля для этого конкретного случая использования кажется слишком сложным.
Что мне можно попробовать дальше? Язык не является проблемой, если решение можно реализовать.
У меня был случай, когда мне нужно было создать функцию подписи PDF-файлов с помощью ключа безопасности. Для этого я использую Yubikey 5A и его библиотеку yubico-piv-tool. Я собрал код, используя различные ресурсы, но до сих пор не могу получить конечный результат. [code]void signPDF(const char* pdfFilePath, const char* yubikeyPIN) { // Open PDF file HPDF_Doc pdf = HPDF_New(error_handler, NULL); if (!pdf) { fprintf(stderr, "Error: Cannot create PDF object\n"); return; }
// Add a page to the document HPDF_Page page = HPDF_AddPage(pdf);
// Set the font and size HPDF_Font font = HPDF_GetFont(pdf, "Helvetica", NULL); HPDF_Page_SetFontAndSize(page, font, 24);
// Write some text HPDF_Page_BeginText(page); HPDF_Page_TextOut(page, 50, 700, "Not so Random!"); HPDF_Page_EndText(page);
// Save PDF content to stream if (HPDF_OK != HPDF_SaveToStream(pdf)) { fprintf(stderr, "Error: Cannot save PDF to stream\n"); HPDF_Free(pdf); return; }
// Get the size of the stream HPDF_UINT32 contentLen = HPDF_GetStreamSize(pdf);
// Allocate memory for the content HPDF_BYTE *content = (HPDF_BYTE *)malloc(contentLen);
ykpiv_rc res = ykpiv_connect(state, NULL); if (res != YKPIV_OK) { fprintf(stderr, "Error: ykpiv_connect failed with code %d\n", res); return; }
int tries; res = ykpiv_verify(state, yubikeyPIN, &tries); if (res != YKPIV_OK) { fprintf(stderr, "Error: Cannot authenticate with YubiKey\n"); return; }
// Save the signed PDF file if (HPDF_SaveToFile(pdf, "signed_example.pdf") != HPDF_OK) { fprintf(stderr, "Error: Cannot save signed PDF file.\n"); return; }
printf("PDF file signed successfully.\n"); }void signPDF(const char* pdfFilePath, const char* yubikeyPIN) { // Open PDF file HPDF_Doc pdf = HPDF_New(error_handler, NULL); if (!pdf) { fprintf(stderr, "Error: Cannot create PDF object\n"); return; }
// Add a page to the document HPDF_Page page = HPDF_AddPage(pdf);
// Set the font and size HPDF_Font font = HPDF_GetFont(pdf, "Helvetica", NULL); HPDF_Page_SetFontAndSize(page, font, 24);
// Write some text HPDF_Page_BeginText(page); HPDF_Page_TextOut(page, 50, 700, "Not so Random!"); HPDF_Page_EndText(page);
// Save PDF content to stream if (HPDF_OK != HPDF_SaveToStream(pdf)) { fprintf(stderr, "Error: Cannot save PDF to stream\n"); HPDF_Free(pdf); return; }
// Get the size of the stream HPDF_UINT32 contentLen = HPDF_GetStreamSize(pdf);
// Allocate memory for the content HPDF_BYTE *content = (HPDF_BYTE *)malloc(contentLen);
ykpiv_rc res = ykpiv_connect(state, NULL); if (res != YKPIV_OK) { fprintf(stderr, "Error: ykpiv_connect failed with code %d\n", res); return; }
int tries; res = ykpiv_verify(state, yubikeyPIN, &tries); if (res != YKPIV_OK) { fprintf(stderr, "Error: Cannot authenticate with YubiKey\n"); return; }
// Save the signed PDF file if (HPDF_SaveToFile(pdf, "signed_example.pdf") != HPDF_OK) { fprintf(stderr, "Error: Cannot save signed PDF file.\n"); return; }
printf("PDF file signed successfully.\n"); } [/code] По сути, код создает документ с одной страницей (это не совсем важно, поскольку, когда я разберусь с подписью, я смогу загрузить PDF-документ прямо из хранилище) и подписывает его содержимое с помощью закрытого ключа в Yubikey. Но моя проблема в том, что я не могу понять, как добавить этот подписанный контент в правильные диапазоны байтов в PDF. Я пробовал использовать библиотеку PoDoFo, но, похоже, это необходимо работайте только с заранее доступным закрытым ключом, что сводит на нет всю цель, поскольку ключ в любом случае не следует вынимать из YubiKey. Я пытался разобраться в том, как подписываются PDF-файлы, но создание функциональности с нуля для этого конкретного случая использования кажется слишком сложным. Что мне можно попробовать дальше? Язык не является проблемой, если решение можно реализовать.