OpenSSL proporciona libcrypto y libssl para C y, a través de enlaces (bindings), para Node.js, Python, PHP y Ruby, además del comando openssl, que es lo primero con lo que se encuentra la mayoría. Los datos de esta página se comprobaron con el paquete de la distribución Alpine 3.24.2, OpenSSL 3.5.9 (la rama 3.5 de soporte a largo plazo); las versiones más recientes del proyecto en ese momento eran la 3.6.5 y la 4.0.3, así que el comportamiento puede diferir en ellas.
Las firmas ECDSA de EVP_DigestSign y de openssl dgst -sign son DER ASN.1, de 70 a 72 bytes en P-256. Los nonces son aleatorios salvo que establezcas el parámetro nonce-type en 1 (OpenSSL 3.2+), lo que reprodujo el vector de prueba P-256 del RFC 6979; en la línea de comandos ese parámetro solo es accesible mediante pkeyutl, como muestra el ejemplo. s no se normaliza y la verificación acepta high-S. EVP_PKEY_sign firma un resumen que calculas tú.
Una entrada mal formada es un error, no un resultado falso: EVP_DigestVerify devolvió -1 con una firma r‖s en bruto de 64 bytes, y la CLI lo indicó así. openssl dgst -verify imprimió Verified OK para una firma correcta, Verification failure para una firma válida sobre otros datos y Error verifying data para 64 bytes que no son DER, así que en la 3.5.9 un problema de formato se distingue de una falsificación por el texto del mensaje. Convierte las firmas en bruto con el conversor DER ⇄ en bruto, o deja que el constructor de comandos OpenSSL componga la invocación correcta.
Las curvas incluyen de P-224 a P-521, secp256k1 y las curvas Brainpool r1, además de Ed25519 y Ed448. Desde la 3.5, el proveedor predeterminado también implementa ML-KEM, ML-DSA y SLH-DSA, y el grupo TLS híbrido X25519MLKEM768. Las claves privadas llegan como PKCS#8 (sin cifrar o cifrado) o SEC1, y las claves públicas como SPKI o dentro de un certificado: genpkey escribe -----BEGIN PRIVATE KEY-----, y el heredado openssl ec escribe -----BEGIN EC PRIVATE KEY-----; un archivo con la etiqueta EC siempre es una clave privada.
La mayoría de los mensajes de error que la gente busca provienen de la carga de claves —no start line, header too long, unsupported del decodificador— y se explican en las páginas de errores enlazadas.