How to create certificate with undefined validity period - go

If I omit the attribute NotAfter during initialisation of an x509.Certificate, it results in the expiry date being set to "0001-01-01", thus making the certificate expired.
In PHP + phpseclib, I can skip setting this field, making the issued certificate never expire. Is it possible to do this in Go?
RFC 5280 states:
4.1.2.5. Validity To indicate that a certificate has no well-defined expiration date, the notAfter SHOULD be assigned the GeneralizedTime value of 99991231235959Z.
How can I do this in Go?

TL;DR: Neither NotBefore nor NotAfter is optional. You must be mistaken about your Python PHP script. I would assume it uses some kind of default value for NotAfter if you don't specify it.
crypto/x509 defines the Validity as follows:
type validity struct {
NotBefore, NotAfter time.Time
}
Since neither field is a pointer, they cannot be undefined.
If you want to force the issue, you can use a modified copy of the x509 types to encode a certificate without the NotAfter field, but the result is unusable. Playground link
package main
import (
"crypto/ecdsa"
"crypto/elliptic"
"crypto/rand"
"crypto/x509"
"crypto/x509/pkix"
"encoding/asn1"
"encoding/pem"
"log"
"math/big"
"os"
"time"
)
// copy of x509.certificate, with TBSCertificate.Validity.NotAfter omitted
type certificate struct {
TBSCertificate struct {
Version int `asn1:"optional,explicit,default:0,tag:0"`
SerialNumber *big.Int
SignatureAlgorithm pkix.AlgorithmIdentifier
Issuer asn1.RawValue
Validity struct {
NotBefore time.Time
}
Subject asn1.RawValue
PublicKey struct {
Raw asn1.RawContent
Algorithm pkix.AlgorithmIdentifier
PublicKey asn1.BitString
}
UniqueId asn1.BitString `asn1:"optional,tag:1"`
SubjectUniqueId asn1.BitString `asn1:"optional,tag:2"`
Extensions []pkix.Extension `asn1:"optional,explicit,tag:3"`
}
SignatureAlgorithm pkix.AlgorithmIdentifier
SignatureValue asn1.BitString
}
func main() {
derBytes := generateSelfSigned()
// re-marshal to remove the NotAfter field
var c certificate
_, err := asn1.Unmarshal(derBytes, &c)
check(err)
derBytes, err = asn1.Marshal(c)
check(err)
pem.Encode(os.Stdout, &pem.Block{
Type: "CERTIFICATE",
Bytes: derBytes,
})
}
func generateSelfSigned() (derBytes []byte) {
pk, err := ecdsa.GenerateKey(elliptic.P224(), rand.Reader)
check(err)
tpl := &x509.Certificate{SerialNumber: big.NewInt(1)}
derBytes, err = x509.CreateCertificate(rand.Reader, tpl, tpl, &pk.PublicKey, pk)
check(err)
return derBytes
}
func check(err error) {
if err != nil {
log.Fatal(err)
}
}
If you hand one of these certificates to openssl, for instance, parsing fails as expected with
unable to load certificate
139990566643520:error:0D078079:asn1 encoding routines:asn1_item_embed_d2i:field missing:crypto/asn1/tasn_dec.c:389:Field=notAfter, Type=X509_VAL

Related

JWT Claims not retained after token signing

I have the following code. I am creating a json web token (using golang-jwt) with custom claims. The issue is that when I sign the token with a key (method = HS256) and then parse the token the claims are getting changed. What mistake I am making.
Code:
package main
import (
"fmt"
"time"
"github.com/golang-jwt/jwt/v4"
)
type MyCustomClaims struct {
userid int
jwt.RegisteredClaims
}
func (app *Config) generateJWT(userid int) {
//Code to generate jwt
jt := jwt.NewWithClaims(jwt.SigningMethodHS256, MyCustomClaims{
userid,
jwt.RegisteredClaims{
ExpiresAt: jwt.NewNumericDate(time.Now().Add(3 * time.Hour)),
IssuedAt: jwt.NewNumericDate(time.Now()),
},
})
fmt.Println("What was put", jt.Claims.(MyCustomClaims).userid)
token, _ := jt.SignedString(app.secret)
//Code to check whether claims are retained
parsed_token, _ := jwt.ParseWithClaims(token, &MyCustomClaims{}, func(t *jwt.Token) (interface{}, error) {
return app.secret, nil
})
fmt.Println("What was parsed", parsed_token.Claims.(*MyCustomClaims).userid)
}
Output
What was put 8
What was parsed 0
You have to export the userid field (make it start with a capital letter). Unexported fields cannot be JSON encoded.
type MyCustomClaims struct {
UserID int `json:"userid"`
jwt.RegisteredClaims
}

Generate Video Access token (JWT) with Twillio Go SDK

I am failing to create an Access Token for the Twillio Video Product with the golang SDK
In the docs there is golang sadly not mentioned
Does anyone of you know how I can create the required access token?
The JWT package mentioned in the examples of the other languages can not be found in the Go SDK.
I found that it is just not possible to do it with the default go SDK. I did follow the instructions on https://www.twilio.com/docs/iam/access-tokens and build the JWT myself. Maybe someone will find the solution handy:
package main
import (
"encoding/json"
"fmt"
"github.com/dvsekhvalnov/jose2go"
"log"
"time"
)
func main() {
accountSid := "XXX"
keySid := "YYY"
keySecret := "ZZZ"
username := "Simon"
roomName := "SimonsRoom"
now := time.Now()
type JWTPayload struct {
Jti string `json:"jti"`
Issuer string `json:"iss"`
Subject string `json:"sub"`
CreationUnixTimestamp int64 `json:"iat"`
NotBeforeUnixTimestamp int64 `json:"nbf"`
ExpiresUnixTimestamp int64 `json:"exp"`
Grants struct {
Identity string `json:"identity"`
Video struct {
Room string `json:"room"`
} `json:"video"`
} `json:"grants"`
}
payload := JWTPayload{
Jti: fmt.Sprintf("%s-%d",keySid,now.UnixNano()),
Issuer: keySid,
Subject: accountSid,
CreationUnixTimestamp: now.Unix(),
NotBeforeUnixTimestamp: now.Unix(),
ExpiresUnixTimestamp: now.Add(23*time.Hour).Unix(),
Grants: struct {
Identity string `json:"identity"`
Video struct {
Room string `json:"room"`
} `json:"video"`
}{
Identity: username,
Video: struct {
Room string `json:"room"`
}{
Room: roomName,
},
},
}
payloadByte, err := json.Marshal(payload)
if err != nil {
log.Fatal(err)
}
token, err := jose.SignBytes(payloadByte, jose.HS256, []byte(keySecret),
jose.Header("cty", "twilio-fpa;v=1"),
jose.Header("typ", "JWT"),
jose.Header("alg", "HS256"),
)
if err != nil {
log.Fatal(err)
}
fmt.Println(token)
}

How to validate API key with function in Martini?

So I currently have a function that will take in a string APIKey to check it against my Mongo collection. If nothing is found (not authenticated), it returns false - if a user is found, it returns true. My problem, however, is I'm unsure how to integrate this with a Martini POST route. Here is my code:
package main
import (
"context"
"fmt"
"log"
"os"
"github.com/go-martini/martini"
_ "github.com/joho/godotenv/autoload"
"go.mongodb.org/mongo-driver/bson"
"go.mongodb.org/mongo-driver/mongo"
"go.mongodb.org/mongo-driver/mongo/options"
)
type User struct {
Name string
APIKey string
}
func validateAPIKey(users *mongo.Collection, APIKey string) bool {
var user User
filter := bson.D{{"APIKey", APIKey}}
if err := users.FindOne(context.TODO(), filter).Decode(&user); err != nil {
fmt.Printf("Found 0 results for API Key: %s\n", APIKey)
return false
}
fmt.Printf("Found: %s\n", user.Name)
return true
}
func uploadHandler() {
}
func main() {
mongoURI := os.Getenv("MONGO_URI")
mongoOptions := options.Client().ApplyURI(mongoURI)
client, _ := mongo.Connect(context.TODO(), mongoOptions)
defer client.Disconnect(context.TODO())
if err := client.Ping(context.TODO(), nil); err != nil {
log.Fatal(err, "Unable to access MongoDB server, exiting...")
}
// users := client.Database("sharex_api").Collection("authorized_users") // commented out when testing to ignore unused warnings
m := martini.Classic()
m.Post("/api/v1/upload", uploadHandler)
m.RunOnAddr(":8085")
}
The validateAPIKey function works exactly as intended if tested alone, I am just unsure how I would run this function for a specific endpoint (in this case, /api/v1/upload).

Converting rsa.PublicKey to ssh.PublicKey

I have an rsa.PublicKey which consists of a modulus and a public exponenet in a struct. I want to verify an ssh.Signature which is signed with that key, and I figure if I have an ssh.PublicKey I can call the Verify method on that interface. However, I can't find any classes that implement ssh.PublicKey and support converting from rsa.PublicKey. Do I need to write a proprietary method to do this, or is there some class I'm not finding, or a better way to go about solving my problem?
For context, I got the rsa.PublicKey from an x509.Certificate which came from a yubikey attesting a key in one of its PIV slots.
The NewPublicKey function from the crypto/ssh package http://godoc.org/golang.org/x/crypto/ssh#NewPublicKey can take an *rsa.PublicKey as parameter and returns an instance of the PublicKey interface that includes a Verify method (Verify(data []byte, sig *Signature) error) - http://godoc.org/golang.org/x/crypto/ssh#PublicKey.
The program below illustrates it - we create a new *rsa.PrivateKey and sign a message with it, then convert *rsa.PublicKey to ssh.PublicKey using NewPublicKey function and verify the signature; also check that the signature verification fails if the original data is modified. The error checking is elided for brevity.
package main
import (
"crypto/rand"
"crypto/rsa"
"fmt"
"log"
"golang.org/x/crypto/ssh"
)
func main() {
data := []byte("Hello, world!")
// create a new key as *rsa.PrivateKey
priv, _ := rsa.GenerateKey(rand.Reader, 512)
signer, _ := ssh.NewSignerFromKey(priv)
sig, _ := signer.Sign(rand.Reader, data)
// extract the ssh.PublicKey from *rsa.PublicKey to verify the signature
pub, _ := ssh.NewPublicKey(&priv.PublicKey)
if err := pub.Verify(data, sig); err != nil {
log.Fatalf("publicKey.Verify failed: %v", err)
}
fmt.Printf("Signature OK\n")
// modify the data and make sure we get a failure
data[0]++
if err := pub.Verify(data, sig); err == nil {
log.Printf("publicKey.Verify passed on bad data/signature, expect failure")
}
}
Output:
Signature OK

how to access deeply nested json keys and values

I'm writing a websocket client in Go. I'm receiving the following JSON from the server:
{"args":[{"time":"2013-05-21 16:57:17"}],"name":"send:time"}
I'm trying to access the time parameter, but just can't grasp how to reach deep into an interface type:
package main;
import "encoding/json"
import "log"
func main() {
msg := `{"args":[{"time":"2013-05-21 16:56:16", "tzs":[{"name":"GMT"}]}],"name":"send:time"}`
u := map[string]interface{}{}
err := json.Unmarshal([]byte(msg), &u)
if err != nil {
panic(err)
}
args := u["args"]
log.Println( args[0]["time"] ) // invalid notation...
}
Which obviously errors, since the notation is not right:
invalid operation: args[0] (index of type interface {})
I just can't find a way to dig into the map to grab deeply nested keys and values.
Once I can get over grabbing dynamic values, I'd like to declare these messages. How would I write a type struct to represent such complex data structs?
You may like to consider the package github.com/bitly/go-simplejson
See the doc: http://godoc.org/github.com/bitly/go-simplejson
Example:
time, err := json.Get("args").GetIndex(0).String("time")
if err != nil {
panic(err)
}
log.Println(time)
The interface{} part of the map[string]interface{} you decode into will match the type of that field. So in this case:
args.([]interface{})[0].(map[string]interface{})["time"].(string)
should return "2013-05-21 16:56:16"
However, if you know the structure of the JSON, you should try defining a struct that matches that structure and unmarshal into that. Ex:
type Time struct {
Time time.Time `json:"time"`
Timezone []TZStruct `json:"tzs"` // obv. you need to define TZStruct as well
Name string `json:"name"`
}
type TimeResponse struct {
Args []Time `json:"args"`
}
var t TimeResponse
json.Unmarshal(msg, &t)
That may not be perfect, but should give you the idea
I'm extremely new to Golang coming from Python, and have always struggled with encode/decoding json. I found gjson at https://github.com/tidwall/gjson, and it helped me immensely:
package main
import "github.com/tidwall/gjson"
func main() {
msg := (`{"args":[{"time":"2013-05-21 16:56:16", "tzs":[{"name":"GMT"}]}],"name":"send:time"}`)
value := gjson.Get(msg, "args.#.time")
println(value.String())
}
-----------------------
["2013-05-21 16:56:16"]
Additionally, I noticed the comment of how to convert into Struct
package main
import (
"encoding/json"
"fmt"
)
type msgFormat struct {
Time string `json:"time"`
Tzs msgFormatTzs `json:"tzs"`
Name string `json:"name"`
}
type msgFormatTzs struct {
TzsName string `json:"name"`
}
func main() {
msg := (`{"args":[{"time":"2013-05-21 16:56:16", "tzs":[{"name":"GMT"}]}],"name":"send:time"}`)
r, err := json.Marshal(msgFormatTzs{msg})
if err != nil {
panic(err)
}
fmt.Printf("%v", r)
}
Try on Go playground

Resources