I need to create and sign (I am CA) certificate with custom subject (, SERIALNUMBER=...,).
So far I have modified openssl config file so I am able to inclde custom fields in subject.
[ new_oids ]
SERIALNUMBER = 1.2.3.4.1333
Problem is, that after signing such certificate new fields appear in that strange number format -
C = FI
O = Maahanmuuttovirasto
1.2.3.4.1333 = 00REINIS00
where and what should I change in my openssl config file to generate certificate with normal field names? How do I tell to signing process that 1.2.3.4.1333 should be encoded as 'SERIALNUMBER'.
Thank you,
Beef
That is actually no error at all. What gets stored in the certificate's subject is a DistinguishedName. Cf. RFC 5280
TBSCertificate ::= SEQUENCE {
version [0] Version DEFAULT v1,
serialNumber CertificateSerialNumber,
signature AlgorithmIdentifier,
issuer Name,
validity Validity,
subject Name,
subjectPublicKeyInfo SubjectPublicKeyInfo,
issuerUniqueID [1] IMPLICIT UniqueIdentifier OPTIONAL,
-- If present, version MUST be v2 or v3
subjectUniqueID [2] IMPLICIT UniqueIdentifier OPTIONAL,
-- If present, version MUST be v2 or v3
extensions [3] Extensions OPTIONAL
-- If present, version MUST be v3 -- }
So the subject is a Name, this is defined as
Name ::= CHOICE { -- only one possibility for now --
rdnSequence RDNSequence }
RDNSequence ::= SEQUENCE OF RelativeDistinguishedName
RelativeDistinguishedName ::= SET SIZE (1..MAX) OF AttributeTypeAndValue
AttributeTypeAndValue ::= SEQUENCE {
type AttributeType,
value AttributeValue }
AttributeType ::= OBJECT IDENTIFIER
AttributeValue ::= ANY -- DEFINED BY AttributeType
So as you can see, the subject consists of a sequence of RelativeDistingsuishedNames, that each represent a pair of an oid plus the assigned value. That implies that nowhere in your certificate 'SERIALNUMBER' will be stored, but only the value for the oid, 1.2.3.4.1333. It's up to applications to interpret these oids as something meaningful and there are a number of common oids that most applications know and will represent using a string, such as "C", "O", "OU", "CN" and so on ( cf. RFC 2253 or RFC 1779).
But 'SERIALNUMBER' is unknown to OpenSSL by default, in fact, you are adding it to new_oidsyourself. Due to this, OpenSSL does not know how to represent 'SERIALNUMBER' other than by printing the OID itself. But any other software that is aware of 'SERIALNUMBER' (IIRC Windows/IE is) will display this correctly as being the value of 'SERIALNUMBER'.
Related
Lets take this URL for example
https://<ip>/restconf/data/Cisco-IOS-XE-native:native/interface/GigabitEthernet=1
If i send a request to a similar endpoint using the internal library we've been using the server doesn't understand it since the = is encoded to %3D but making the same request on the CLI with curl works fine.
I'm not understanding why it's an issue, isn't = supposed to be encoded in a URL anyway? Is it something to do with the library treating it as a query?
The = represents a special character with special meaning in a RESTCONF URI. If you encode it as %3D, you take that special meaning away and reduce it to just a character. The only case where you would do that is when a list's key value or a leaf-list's value contain this character and you are referencing such an instance in your URI.
You are only allowed to use = when referencing list and leaf-list instances - and you do not percent encode it when you do use it.
In your case, GigabitEthernet would be expected to represent a list/leaf-list, with its key/type accepting 1 as a valid value. Both native and interface would be (and can only be) containers (or anydata).
RFC8040, Section 3.5.3, Encoding Data Resource Identifiers in the Request URI describes this in detail.
Here are the examples from the same section:
Examples:
container top {
list list1 {
key "key1 key2 key3";
...
list list2 {
key "key4 key5";
...
leaf X { type string; }
}
}
leaf-list Y {
type uint32;
}
}
For the above YANG definition, the container "top" is defined in the
"example-top" YANG module, and a target resource URI for leaf "X"
would be encoded as follows:
/restconf/data/example-top:top/list1=key1,key2,key3/list2=key4,key5/X
For the above YANG definition, a target resource URI for
leaf-list "Y" would be encoded as follows:
/restconf/data/example-top:top/Y=instance-value
The following example shows how reserved characters are
percent-encoded within a key value. The value of "key1" contains
a comma, single-quote, double-quote, colon, double-quote, space,
and forward slash (,'":" /). Note that double-quote is not a
reserved character and does not need to be percent-encoded. The
value of "key2" is the empty string, and the value of "key3" is the
string "foo".
Example URL:
/restconf/data/example-top:top/list1=%2C%27"%3A"%20%2F,,foo
Note the last example in particular. You would need to percent encode a =, if it appears after list1= in its key value.
Note that also that these are not parts of a query - they are path segments (RFC3986 terms).
What is the format of the public_key field returned from GitHub REST API v3 for GPG Keys?
For example, the command curl -v -H "Accept: application/vnd.github.cryptographer-preview" https://api.github.com/users/DurandA/gpg_keys returns the following keys:
pub dsa2048/403094DF 2017-09-03 [SC] [expires: 2018-09-03]
uid [ultimate] Arnaud Durand <arnaud.durand#unifr.ch>
sub elg2048/A454F414 2017-09-03 [E] [expires: 2018-09-03]
According to the API doc:
The data returned in the public_key response field is not a GPG formatted key. When a user uploads a GPG key, it is parsed and the cryptographic public key is extracted and stored. This cryptographic key is what is returned by the APIs on this page. This key is not suitable to be used directly by programs like GPG.
Is it possible to use these keys from a CLI or programmatically?
The key returned is a bare (RSA, DSA, ...) key, which cannot be used by implementations of OpenPGP without "wrapping" it in a proper OpenPGP key packet again. I would not recommend to do so, why you should be able to construct the key packet again, you will have no chance in constructing binding signatures for subkeys and user IDs (this requires access to the private keys) and will not succeed and constructing something useful therefor.
The "OpenPGP model" of sharing keys in communities is fetching a current copy from the key server network (including all current certifications and revocations) instead of relying on possibly outdated versions in "third-party-locations" like GitHub. This is possible by fingerprints and key IDs that (more or less uniquely, see below) address specific keys -- do not search for mail addresses, everybody can create keys with arbitrary user IDs and keyservers do not perform any validation.
Instead, have another look at the APIs output, which returns keyid objects for all keys (some for subkeys):
[
{
"id": 3,
"primary_key_id": null,
"key_id": "3262EFF25BA0D270",
"public_key": "xsBNBFayYZ...",
"emails": [
{
"email": "mastahyeti#users.noreply.github.com",
"verified": true
}
],
[snip]
}
]
To use such a key ID, run gpg --recv-keys <key-id>. And drop GitHub a note to follow best practices and include the full fingerprint:
These 64-bit hex values (3262EFF25BA0D270 in this example) are long key IDs. While any programmatic references to keys should always include the key's fingerprint, not abbreviated key IDs, at least they do not provide short key IDs that heavily suffer under collision attacks.
As of writing, contents in public_key fields are base64-encoded OpenPGP packets, which are defined in RFC 4880. gpgpdump is useful to inspect them. For example,
$ curl -s https://api.github.com/users/DurandA/gpg_keys | jq -r '.[0].public_key' | base64 -d | ./gpgpdump
Public-Key Packet (tag 6) (814 bytes)
Version: 4 (current)
Public key creation time: 2017-09-04T06:53:50+08:00
59 ac 87 fe
Public-key Algorithm: DSA (Digital Signature Algorithm) (pub 17)
DSA p (2048 bits)
DSA q (q is a prime divisor of p-1) (256 bits)
DSA g (2046 bits)
DSA y (= g^x mod p where x is secret) (2047 bits)
As an OpenPGP key is composed of a series of OpenPGP packets, it is theoretically possible to reconstruct a key for verifying stuffs. To achieve that, an extra user ID packet and a GnuPG patch are needed. The following Python 3 script can be used to generate a user ID packet:
TAG_UID = 13
uid = 'foo#example.com'
# RFC 4880, Sec 4.2.1. Old Format Packet Lengths
header = bytes([0x80 | (TAG_UID << 2), len(uid)])
packet = header + uid.encode('ascii')
sys.stdout.buffer.write(packet)
And the following GnuPG patch forces verification even if there are no signatures.
diff --git a/g10/sig-check.c b/g10/sig-check.c
index 4c172d692..eb4653535 100644
--- a/g10/sig-check.c
+++ b/g10/sig-check.c
## -177,7 +177,7 ## check_signature2 (ctrl_t ctrl,
gnupg_compliance_option_string (opt.compliance));
rc = gpg_error (GPG_ERR_PUBKEY_ALGO);
}
- else if (!pk->flags.valid)
+ else if (0)
{
/* You cannot have a good sig from an invalid key. */
rc = gpg_error (GPG_ERR_BAD_PUBKEY);
Anyway, as there are no self-signatures, the verification result should not trusted.
I don't understand why JWS unprotected headers exist.
For some context: a JWS unprotected header contains parameters that are not integrity protected and can only be used per-signature with JSON Serialization.
If they could be used as a top-level header, I could see why someone could want to include a mutable parameter (that wouldn't change the signature). However, this is not the case.
Can anyone think of a use-case or know why they are included in the spec?
Thanks!
JWS Spec
The answer by Florent leaves me unsatisfied.
Regarding the example of using a JWT to sign a hash of a document... the assertion is that the algorithm and keyID would be "sensitive data" that needs to be "protected". By which I suppose he means "signed". But there's no need to sign the algorithm and keyID.
Example
Suppose Bob creates a signed JWT, that contains an unprotected header asserting alg=HS256 and keyid=XXXX1 . This JWT is intended for transmission to Alice.
Case 1
Suppose Mallory intercepts the signed JWT sent by Bob. Mallory then creates a new unprotected header, asserting alg=None.
The receiver (Alice) is now responsible for verifying the signature on the payload. Alice must not be satisfied with "no signature"; in fact Alice must not rely on a client (sender) assertion to determine which signing algorithm is acceptable for her. Therefore Alice rejects the JWT with the contrived "no signature" header.
Case 2
Suppose Mallory contrives a header with alg=RS256 and keyId=XXX1. Now Alice tries to validate the signature and finds either:
the algorithm is not compliant
the key specified for that algorithm does not exist
Therefore Alice rejects the JWT.
Case 3
Suppose Mallory contrives a header with alg=HS256 and keyId=ZZ3. Now Alice tries to validate the signature and finds the key is unknown, and rejects the JWT.
In no case does the algorithm need to be part of the signed material. There is no scenario under which an unprotected header leads to a vulnerability or violation of integrity.
Getting Back to the Original Question
The original question was: What is the purpose of an unprotected JWT header?
Succinctly, the purpose of an unprotected JWS header is to allow transport of some metadata that can be used as hints to the receiver. Like alg (Algorithm) and kid (Key ID). Florent suggests that stuffing data into an unprotected header could lead to efficiency. This isn't a good reason. Here is the key point: The claims in the unprotected header are hints, not to be relied upon or trusted.
A more interesting question is: What is the purpose of a protected JWS header? Why have a provision that signs both the "header" and the "payload"? In the case of a JWS Protected Header, the header and payload are concatenated and the result is signed. Assuming the header is JSON and the payload is JSON, at this point there is no semantic distinction between the header and payload. So why have the provision to sign the header at all?
One could just rely on JWS with unprotected headers. If there is a need for integrity-protected claims, put them in the payload. If there is a need for hints, put them in the unprotected header. Sign the payload and not the header. Simple.
This works, and is valid. But it presumes that the payload is JSON. This is true with JWT, but not true with all JWS. RFC 7515, which defines JWS, does not require the signed payload to be JSON. Imagine the payload is a digital image of a medical scan. It's not JSON. One cannot simply "attach claims" to that. Therefore JWS allows a protected header, such that the (non JSON) payload AND arbitrary claims can be signed and integrity checked.
In the case where the payload is non-JSON and the header is protected, there is no facility to include "extra non signed headers" into the JWS. If there is a need for sending some data that needs to be integrity checked and some that are simply "hints", there really is only one container: the protected header. And the hints get signed along with the real claims.
One could avoid the need for this protected-header trick, by just wrapping a JSON hash around the data-to-be-signed. For example:
{
"image" : "qw93u9839839...base64-encoded image data..."
}
And after doing so, one could add claims to this JSON wrapper.
{
"image" : "qw93u9839839...base64-encoded image data..."
"author" : "Whatever"
}
And those claims would then be signed and integrity-proected.
But in the case of binary data, encoding it to a string to allow encapsulation into a JSON may inflate the data significantly. A JWS with a non-JSON payload avoids this.
HTH
The RFC gives us examples of unprotected headers as follows:
A.6.2. JWS Per-Signature Unprotected Headers
Key ID values are supplied for both keys using per-signature Header Parameters. The two JWS Unprotected Header values used to represent these key IDs are:
{"kid":"2010-12-29"}
and
{"kid":"e9bc097a-ce51-4036-9562-d2ade882db0d"}
https://datatracker.ietf.org/doc/html/rfc7515#appendix-A.6.2
The use of kid in the example is likely not coincidence. Because JWS allows multiple signatures per payload, a cleartext hint system could be useful. For example, if a key is not available to the verifier (server), then you can skip decoding the protected header. The term "hint" is actually used in the kid definition:
4.1.4. "kid" (Key ID) Header Parameter
The "kid" (key ID) Header Parameter is a hint indicating which key was used to secure the JWS. This parameter allows originators to explicitly signal a change of key to recipients. The structure of the "kid" value is unspecified. Its value MUST be a case-sensitive string. Use of this Header Parameter is OPTIONAL.
https://datatracker.ietf.org/doc/html/rfc7515#section-4.1.4
If we look at Key Identification it mentions where you a kid does not have to be integrity protected (ie: part of unprotected headers): (emphasis mine)
6. Key Identification
It is necessary for the recipient of a JWS to be able to determine the key that was employed for the digital signature or MAC operation. The key employed can be identified using the Header Parameter methods described in Section 4.1 or can be identified using methods that are outside the scope of this specification. Specifically, the Header Parameters "jku", "jwk", "kid", "x5u", "x5c", "x5t", and "x5t#S256" can be used to identify the key used. These Header Parameters MUST be integrity protected if the information that they convey is to be utilized in a trust decision; however, if the only information used in the trust decision is a key, these parameters need not be integrity protected, since changing them in a way that causes a different key to be used will cause the validation to fail.
The producer SHOULD include sufficient information in the Header Parameters to identify the key used, unless the application uses another means or convention to determine the key used. Validation of the signature or MAC fails when the algorithm used requires a key (which is true of all algorithms except for "none") and the key used cannot be determined.
The means of exchanging any shared symmetric keys used is outside the scope of this specification.
https://datatracker.ietf.org/doc/html/rfc7515#section-6
Simplified, if you have a message that by somebody modifying the kid will refer to another key, then the signature itself will not match. Therefore you don't have to include the kid in the protected header. A good example of the first part, where the information they convey is to be utilized in a trust decision, is the ACME (aka the Let's Encrypt protocol). When creating an account, and storing the key data, you want to trust the kid. We want to store kid, so we need to make sure it's valid. After the server has stored the kid and can use it to get a key, we can push messages and reference the kid in unprotected header (not done by ACME but possible). Since we're only going to verify the signature, then the kid is used a hint or reference to which kid was used for the account. If that field is tampered with, then it'll point to a nonexistent of completely different key and fail the signature the check. That means the kid itself is "the only information used in the trust decision".
There's also more theoretical scenarios that, knowing how it works you can come up with.
For example: the idea of having multiple signatures that you can pass on (exchange). A signing authority can include one signature that can be for an intermediary (server) and another for the another recipient (end-user client). This is differentiated by the kid and the server doesn't need to verify or even decode the protected header or signature. Or perhaps, the intermediary doesn't have the client's secret in order to verify a signature.
For example, a multi-recipient message (eg: chat room) could be processed by a relay/proxy and using kid in the unprotected header, pass along a reconstructed compact JWS (${protected}.${payload}.${signature}) for each recipient based on kid (or any other custom unprotected header field, like userId or endpoint).
Another example, would be a server with access to many different keys and a cleartext kid would be faster than iterating and decoded each protected field to find which one.
From one perspective, all you're doing is skipping base64url decoding the protected header for performance, but if you're going to proxy/relay the data, then you're not polluting the protected header which is meant for another recipient.
In our application we generate certificates for internal entities like platform and user. Our internal entities are identified by custom DNs:
Platform DN: p=platformName
User DN: cn=userName,p=platformName
We tried to generate X.509 certificate for platform or user with popular tools like openssl, keytool, implementation of javax.security (BouncyCastle), e.g.:
keytool -genkey -dname "p=platformName" -alias platformName
However, those tools do not accept/recognize keyword "P" or require certain keywords like "CN" in certificate subject DN.
How to issue certificate to an entity with custom DN format?
Note: We do not need to have DNs containing standard keywords (CN, OU, etc.), because all certificates will be for internal use of our products (will not be validated by 3rd party or included in certificate chain).
We do not need to have DNs containing standard keywords (CN, OU, etc.)
How to issue certificate to an entity with custom DN format?
The attributes or fields displayed are a presentation level detail. There is no distinguished DN field per se. The fields used to form the DN are a mashup of other attributes and are arbitrarily chosen. The common ones are C, O, OU, CN, etc.
Attributes or fields like C, O, OU, CN have well known OIDs associated with them. There are other OIDs you can use that are recognized by tools. For example, the ITU's X.520 list hundreds of them. There are other standards that declare them too. For example, the email address attribute is from PKCS 9 and has an OID of 1.2.840.113549.1.9.1.
As Burhan Khalid stated, you can even add your own name/value pairs by making up OIDs (some hand waiving). However, other presentation tools won't know how to display them. That is, they won't know the "friendly name".
Because other tools don't recognize your OID for platform (or "p=..."), that's why you are getting ... those tools do not accept/recognize keyword "P". The tools don't know how to deal with your custom attributes.
I can only speak for openssl, as I am not familiar with other tools.
From the openssl docs
ASN1 OBJECT CONFIGURATION MODULE
This module has the name oid_section. The value of this variable
points to a section containing name value pairs of OIDs: the name is
the OID short and long name, the value is the numerical form of the
OID. Although some of the openssl utility sub commands already have
their own ASN1 OBJECT section functionality not all do. By using the
ASN1 OBJECT configuration module all the openssl utility sub commands
can see the new objects as well as any compliant applications.
So what you have to do is create these oids in /etc/openssl.conf or wherever the file is for your platform, then openssl will not give you the Subject attribute p has no known NID, skipped message, which I suspect is what you are getting now.
I'm doing a code that has to create a PKCS#10. To do that, I have to sign my "Certificate Request Info", but when I do, the application says that the signature is invalid.
I'm using the OpenSSL.exe to verify the P10, and the error was:
"ANS1_CHECK_TLEN: wrong tag". I think I'm signing what I shouldn't, so my question is, what's the exact format of "Certificate Request Info" that I have to sign?
I know that it must start with a sequence, but the p10 spec tells:
"The signature process consists of two steps:
The value of the certificationRequestInfo component is DER
encoded, yielding an octet string.
The result of step 1 is signed with the certification request
subject’s private key under the specified signature
algorithm, yielding a bit string, the signature."
I'm not sure if the start must be a SEQUENCE (0x30 0x82 "the length>256"), or A OCTET STRING (0x04 0x82 "the length>256"), acording to ANS.1.
If someone please give me an answer like on this post, i could be the happiest man on the world. Thank very much:
PKCS#10 request for a object key pair from PKCS#11
REgards, David M.
The step #1 of the PKCS#10 standard talks about an octet string as the result of the certificationRequestInfo element encoding and does not refer to an ASN.1 type. The request signature is computed on this DER-encoding and therefore the to-be-signed object is an ASN.1 SEQUENCE and not an OCTET STRING.