+
+/**
+ * Check header of an openssh private key and compute bignum offset.
+ *
+ * \param data The base64-decoded key.
+ * \param len The size of the decoded key.
+ *
+ * Several assumptions are made about the key. Most notably, we only support
+ * single unencrypted keys without comments.
+ *
+ * \return The offset at which the first bignum of the private key (the public
+ * exponent n) starts. Negative error code on failure.
+ */
+int find_openssh_bignum_offset(const unsigned char *data, int len)
+{
+ /*
+ * Unencrypted keys without comments always start with the below byte
+ * sequence. See PROTOCOL.key of the openssh package.
+ */
+ static const unsigned char valid_openssh_header[] = {
+ /* string "openssh-key-v1" */
+ 0x6f, 0x70, 0x65, 0x6e, 0x73, 0x73, 0x68, 0x2d, 0x6b, 0x65,
+ 0x79, 0x2d, 0x76, 0x31,
+ /* length of the cipher name */
+ 0x00, 0x00, 0x00, 0x00, 0x04,
+ /* cipher name: "none" */
+ 0x6e, 0x6f, 0x6e, 0x65,
+ /* length of the kdfname (only used for encrypted keys) */
+ 0x00, 0x00, 0x00, 0x04,
+ /* kdfname: "none" */
+ 0x6e, 0x6f, 0x6e, 0x65,
+ /* length of kdfoptions */
+ 0x00, 0x00, 0x00, 0x00,
+ /* number of keys */
+ 0x00, 0x00, 0x00, 0x01,
+ };
+ uint32_t val;
+ const unsigned char *p, *end = data + len;
+
+ if (len <= sizeof(valid_openssh_header) + 4)
+ return -E_OPENSSH_PARSE;
+ if (memcmp(data, valid_openssh_header, sizeof(valid_openssh_header)))
+ return -E_OPENSSH_PARSE;
+ p = data + sizeof(valid_openssh_header);
+ /* length of public key */
+ val = read_u32_be(p);
+ if (val > end - p - 4)
+ return -E_OPENSSH_PARSE;
+ p += val + 4;
+ /* length of private key */
+ val = read_u32_be(p);
+ if (val > end - p - 4)
+ return -E_OPENSSH_PARSE;
+ p += 4;
+ /* two equal random integers ("checkint") */
+ if (p + 8 > end)
+ return -E_OPENSSH_PARSE;
+ if (read_u32_be(p) != read_u32_be(p + 4))
+ return -E_OPENSSH_PARSE;
+ p += 8;
+ /* length of name of key type "ssh-rsa" */
+ if (p + 11 > end)
+ return -E_OPENSSH_PARSE;
+ if (read_u32_be(p) != 7)
+ return -E_OPENSSH_PARSE;
+ if (memcmp(p + 4, "ssh-rsa", 7))
+ return -E_OPENSSH_PARSE;
+ p += 11;
+ return p - data;
+}
+