SSH Keys and PEM Certificates in Base64
SSH keys and TLS certificates travel safely because PEM gives binary data a text envelope.
Every SSH private key and TLS certificate you use is a Base64-wrapped binary structure. The PEM format (Privacy Enhanced Mail) dates from 1993 and uses Base64 to make binary ASN.1 structures transmissible through text channels , email, YAML, environment variables, and config files.1
Between the BEGIN marker and END marker markers sits standard Base64 with 64-character line wrapping. Strip the headers, join the lines, and decode the result to access the raw DER-encoded binary.
How PEM format works
PEM encodes binary key or certificate structures using MIME-compatible Base64 wrapped at a specific line width that differs from the MIME standard of 76 characters. The structure is: a header line (such as BEGIN CERTIFICATE), one or more lines of 64-character Base64, and a footer (such as END CERTIFICATE).1
Matching PEM wrapping to parser expectations
The Base64 uses the standard alphabet (+ and /) with = padding, wrapped at exactly 64 characters per line with LF or CRLF line endings, which is shorter than the 76-character MIME wrapping used for email attachments.2 Consequently, a 2,048-bit RSA private key produces roughly 1,700 bytes of Base64 wrapped across about 27 lines. Building on this, OpenSSH keys (the modern BEGIN OPENSSH PRIVATE KEY marker format) use the same Base64 wrapping but encode a custom OpenSSH binary structure instead of ASN.1. The 64-character line length originates from PEM's roots in email transport, where SMTP line-length limits made shorter lines necessary. Despite the format dating from 1993, the 64-character convention persists because changing it would break compatibility with the vast installed base of OpenSSL and TLS tooling that expects exactly this wrapping width.
This matters because a single over-long line is enough to break a load that works everywhere else. A 76-character PEM that one tool emits will fail an OpenSSL handshake with a generic error, so when a certificate loads in one place and not another, the line width is the first thing to check.
Common pitfalls and variants
PEM line length is 64 characters, not 76 , do not confuse it with MIME Base64's 76-character wrapping.2 Some tools produce 76-character-wrapped PEM files that most TLS libraries reject with an 'invalid PEM format' error. Furthermore, copying PEM keys through terminals, Slack, or email clients often introduces extra whitespace, replaces hyphens with en-dashes, or wraps long lines. Verify that the BEGIN marker and END marker markers use exactly 5 hyphens on each side and that no line contains trailing spaces. A single extra character breaks OpenSSL parsing silently. When converting between PEM and other formats, OpenSSH's ssh-keygen utility can re-wrap keys to the correct line width, and the fold -w 64 command on Linux forces any Base64 string into 64-character lines suitable for PEM encapsulation.
Security and best practice
PEM files containing private keys must never appear in source control, application logs, or API responses. Use .gitignore patterns for *.pem, *.key, and id_rsa. For CI/CD pipelines, store the Base64-encoded PEM in a CI secret variable and decode it at build time: echo $SSH_KEY_B64 | base64 -d > /tmp/id_rsa && chmod 600 /tmp/id_rsa. Furthermore, PKCS#8 (private key in PEM) and PKCS#12 (combined cert+key bundle) require a passphrase for encrypted storage , always use encrypted private keys in production and store the passphrase in a secrets manager, not alongside the key file.3
Keeping private keys out of shared surfaces
Never paste private keys into public issue trackers, chat histories, or build logs while debugging a PEM import error. Use a redacted certificate or a disposable test key when asking for help, then rotate any key that may have been exposed. If a private key does leak, the incident response should include revoking the corresponding certificate, generating a new key pair, and auditing all systems that trusted the compromised certificate, because a leaked private key allows an attacker to impersonate your server or decrypt traffic in transit.
Inspecting and validating PEM files
Inspecting a PEM file with openssl x509 -in cert.pem -text -noout displays the certificate's subject, issuer, validity dates, and public key details without requiring you to decode the Base64 manually.4 For private keys, openssl rsa -in key.pem -check validates the key structure and confirms it is internally consistent. For SSH keys in OpenSSH format, ssh-keygen -y -f id_rsa prints the corresponding public key: a successful output confirms the private key is valid and readable by the SSH toolchain.
Checking PEM line lengths after copying
After copying a PEM file through a terminal, email, or a chat tool, verify that line widths are exactly 64 characters (PEM standard) rather than 76 (MIME standard) by running awk 'length > 64 { print NR": "length" chars" }' cert.pem. Any line exceeding 64 characters indicates a misformatted PEM or a copy-paste line-wrap issue. OpenSSL rejects certificates with incorrect line lengths during TLS handshakes with a generic error that is difficult to trace without this check.
CI/CD SSH key injection patterns
For CI/CD pipelines, the recommended pattern for SSH key injection stores the Base64-encoded key as a CI secret, decodes it to a temporary path in the job step, sets correct permissions, and removes the file after use. A complete GitHub Actions step: echo "${{ secrets.SSH_KEY_B64 }}" | base64 -d > /tmp/id_rsa && chmod 600 /tmp/id_rsa && trap "rm -f /tmp/id_rsa" EXIT. The trap command ensures the key file is removed even when the subsequent step fails.
In GitLab CI, passing the key directly to ssh-add via stdin keeps it only in the SSH agent's memory and never writes it to disk: echo "$SSH_KEY_B64" | base64 -d | ssh-add -. Combining ssh-add - with SSH_AUTH_SOCK environment variable configuration allows subsequent steps to clone and push to Git repositories without accessing the key file again, avoiding the window of vulnerability between writing the key to disk and deleting it after use.5
When to use this
Use PEM (Base64-wrapped) format for TLS certificates, SSH keys, and CSRs when your tooling (OpenSSL, nginx, curl, ssh) expects PEM. Decode the Base64 to DER format when working with languages or libraries that require raw binary keys. For a quick check on a suspect PEM block, strip the header and footer markers and confirm the remaining text produces the DER bytes you expect before trusting the certificate.
Examples
Extract the raw bytes from a PEM certificate
BEGIN CERTIFICATE marker MIIBIjANBgkqhkiG... END CERTIFICATE marker
# Strip headers and decode in bash: openssl x509 -in cert.pem -outform DER -out cert.der # Or manually: grep -v 'BEGIN\|END' cert.pem | tr -d '\n' | base64 -d > cert.der
openssl is the preferred method , it handles encoding quirks that manual base64 -d may not.
Store an SSH key in a CI/CD environment variable
# id_rsa stored as file on build agent
# Encode (single line, no wrapping): export SSH_KEY_B64=$(base64 -w 0 ~/.ssh/id_rsa) # In CI script, decode and use: echo $SSH_KEY_B64 | base64 -d > /tmp/id_rsa chmod 600 /tmp/id_rsa GIT_SSH_COMMAND='ssh -i /tmp/id_rsa' git clone [email protected]:org/repo.git
Clean up /tmp/id_rsa after use with rm -f /tmp/id_rsa.
- 1.
J. Linn, "Privacy Enhancement for Internet Electronic Mail: Part I: Message Encryption and Authentication Procedures," RFC 1421, IETF, February 1993. https://rfc-editor.org/rfc/rfc1421.html
- 2.
S. Josefsson and S. Leonard, "Textual Encodings of PKIX, PKCS, and CMS Structures," RFC 7468, IETF, February 2015. https://rfc-editor.org/rfc/rfc7468.html
- 3.
OpenSSL Project, "openssl-pkcs8," docs.openssl.org, accessed June 2026. https://www.openssl.org/docs/man3.3/man1/openssl-pkcs8.html
- 4.
OpenSSL Project, "openssl-x509," docs.openssl.org, accessed June 2026. https://docs.openssl.org/master/man1/openssl-x509/
- 5.
Linux man-pages project, "ssh-add," man7.org, accessed June 2026. https://man7.org/linux/man-pages/man1/ssh-add.1.html